@khanacademy/perseus 77.11.0 → 78.0.1

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 (33) hide show
  1. package/dist/components/graphie.d.ts +0 -1
  2. package/dist/components/svg-image.d.ts +2 -3
  3. package/dist/es/index.css +2 -2
  4. package/dist/es/index.css.map +1 -1
  5. package/dist/es/index.js +84 -82
  6. package/dist/es/index.js.map +1 -1
  7. package/dist/index.css +2 -2
  8. package/dist/index.css.map +1 -1
  9. package/dist/index.js +84 -82
  10. package/dist/index.js.map +1 -1
  11. package/dist/renderer.d.ts +0 -1
  12. package/dist/server-item-renderer.d.ts +0 -6
  13. package/dist/testing/item-renderer-hooks.d.ts +0 -5
  14. package/dist/types.d.ts +0 -48
  15. package/dist/util/graphie.d.ts +0 -1
  16. package/dist/widget-container.d.ts +0 -1
  17. package/dist/widgets/dropdown/dropdown.d.ts +0 -8
  18. package/dist/widgets/expression/expression.d.ts +0 -16
  19. package/dist/widgets/interactive-graphs/graphs/components/movable-asymptote.d.ts +0 -8
  20. package/dist/widgets/interactive-graphs/graphs/components/movable-line/line.d.ts +0 -2
  21. package/dist/widgets/interactive-graphs/graphs/components/movable-line/movable-line.d.ts +0 -2
  22. package/dist/widgets/interactive-graphs/graphs/components/movable-point.d.ts +0 -2
  23. package/dist/widgets/interactive-graphs/graphs/components/use-control-arrowhead.d.ts +0 -2
  24. package/dist/widgets/interactive-graphs/graphs/components/use-control-point.d.ts +0 -2
  25. package/dist/widgets/interactive-graphs/interactive-graph.d.ts +0 -8
  26. package/dist/widgets/interactive-graphs/types.d.ts +0 -1
  27. package/dist/widgets/label-image/label-image.d.ts +0 -8
  28. package/dist/widgets/mock-widgets/mock-widget.d.ts +0 -8
  29. package/dist/widgets/numeric-input/numeric-input.class.d.ts +0 -8
  30. package/dist/widgets/numeric-input/numeric-input.d.ts +0 -16
  31. package/dist/widgets/table/table.d.ts +0 -8
  32. package/dist/widgets/video/video.d.ts +0 -1
  33. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -1467,7 +1467,7 @@ var a11y = aphrodite.StyleSheet.create({srOnly:{border:0,clip:"rect(0,0,0,0)",he
1467
1467
 
1468
1468
  const debounce=(func,delay)=>{let timer=null;return (...args)=>{if(timer){clearTimeout(timer);}timer=window.setTimeout(()=>{func(...args);},delay);}};
1469
1469
 
1470
- class InnerMathInput extends React__namespace.Component{componentDidMount(){this.mathField()?.latex(this.props.value);}componentDidUpdate(prevProps){if(prevProps.value!==this.props.value){if(this.state.focused){return}const field=this.mathField();if(!field){return}const current=field.latex();if(this.props.value!==current){field.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$D.outerWrapper,this.state.focused&&styles$D.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}`,onClose:()=>this.closeKeypad(),content:()=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.Heading,{size:"large",id:`popover-content-${popoverContentUniqueId}`,style:a11y.srOnly,children:this.context.strings.mathInputDescription}),jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$D.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)=>{if(key==="DISMISS"){this.closeKeypad();return}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();}};}}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.semanticColor.action.primary.progressive.default.foreground;break;case hovered:fillColor=wonderBlocksTokens.semanticColor.action.primary.progressive.hover.background;break;default:fillColor=wonderBlocksTokens.semanticColor.core.foreground.neutral.strong;break}const dynamicClass=active||focused?styles$D.iconActive:styles$D.iconInactive;return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$D.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.semanticColor.core.border.instructive.default,margin:-1};const styles$D=aphrodite.StyleSheet.create({iconContainer:{display:"flex",justifyContent:"center",height:"100%",padding:wonderBlocksTokens.sizing.size_040,borderRadius:1},iconInactive:{border:"2px solid transparent",backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.subtle},iconActive:{border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`,backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.default},outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:wonderBlocksTokens.semanticColor.core.border.neutral.default,borderRadius:3,background:wonderBlocksTokens.semanticColor.core.background.base.default,":hover":inputFocused},wrapperFocused:inputFocused,popoverContent:{padding:0,paddingBottom:wonderBlocksTokens.sizing.size_060,maxWidth:"initial"}});
1470
+ class InnerMathInput extends React__namespace.Component{componentDidMount(){this.mathField()?.latex(this.props.value);}componentDidUpdate(prevProps){if(prevProps.value!==this.props.value){if(this.state.focused){return}const field=this.mathField();if(!field){return}const current=field.latex();if(this.props.value!==current){field.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$E.outerWrapper,this.state.focused&&styles$E.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}`,onClose:()=>this.closeKeypad(),content:()=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.Heading,{size:"large",id:`popover-content-${popoverContentUniqueId}`,style:a11y.srOnly,children:this.context.strings.mathInputDescription}),jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$E.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)=>{if(key==="DISMISS"){this.closeKeypad();return}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();}};}}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.semanticColor.action.primary.progressive.default.foreground;break;case hovered:fillColor=wonderBlocksTokens.semanticColor.action.primary.progressive.hover.background;break;default:fillColor=wonderBlocksTokens.semanticColor.core.foreground.neutral.strong;break}const dynamicClass=active||focused?styles$E.iconActive:styles$E.iconInactive;return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$E.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.semanticColor.core.border.instructive.default,margin:-1};const styles$E=aphrodite.StyleSheet.create({iconContainer:{display:"flex",justifyContent:"center",height:"100%",padding:wonderBlocksTokens.sizing.size_040,borderRadius:1},iconInactive:{border:"2px solid transparent",backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.subtle},iconActive:{border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`,backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.default},outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:wonderBlocksTokens.semanticColor.core.border.neutral.default,borderRadius:3,background:wonderBlocksTokens.semanticColor.core.background.base.default,":hover":inputFocused},wrapperFocused:inputFocused,popoverContent:{padding:0,paddingBottom:wonderBlocksTokens.sizing.size_060,maxWidth:"initial"}});
1471
1471
 
1472
1472
  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};
1473
1473
 
@@ -1479,11 +1479,11 @@ var dependencies = /*#__PURE__*/Object.freeze({
1479
1479
  useDependencies: useDependencies
1480
1480
  });
1481
1481
 
1482
- const ApiOptions={propTypes:PropTypes__default.default.shape({isArticle:PropTypes__default.default.bool.isRequired,onFocusChange:PropTypes__default.default.func.isRequired,showAlignmentOptions:PropTypes__default.default.bool.isRequired,readOnly:PropTypes__default.default.bool.isRequired,answerableCallback:PropTypes__default.default.func,getAnotherHint:PropTypes__default.default.func,interactionCallback:PropTypes__default.default.func,imagePlaceholder:PropTypes__default.default.node,widgetPlaceholder:PropTypes__default.default.node,baseElements:PropTypes__default.default.shape({Link:PropTypes__default.default.func}),imagePreloader:PropTypes__default.default.func,trackInteraction:PropTypes__default.default.func,customKeypad:PropTypes__default.default.bool,nativeKeypadProxy:PropTypes__default.default.func,isMobile:PropTypes__default.default.bool,isMobileApp:PropTypes__default.default.bool,setDrawingAreaAvailable:PropTypes__default.default.func,hintProgressColor:PropTypes__default.default.string,canScrollPage:PropTypes__default.default.bool,editorChangeDelay:PropTypes__default.default.number}).isRequired,defaults:{isArticle:false,isMobile:false,isMobileApp:false,editingDisabled:false,onFocusChange:function(){},showAlignmentOptions:false,readOnly:false,baseElements:{Link:props=>{const{children,...rest}=props;return jsxRuntimeExports.jsx("a",{...rest,children:children})}},setDrawingAreaAvailable:function(){},canScrollPage:false,editorChangeDelay:0}};const ClassNames={RENDERER:"perseus-renderer",TWO_COLUMN_RENDERER:"perseus-renderer-two-columns",RESPONSIVE_RENDERER:"perseus-renderer-responsive",INPUT:"perseus-input",FOCUSED:"perseus-focused",MOBILE:"perseus-mobile"};
1482
+ const ApiOptions={propTypes:PropTypes__default.default.shape({isArticle:PropTypes__default.default.bool.isRequired,onFocusChange:PropTypes__default.default.func.isRequired,showAlignmentOptions:PropTypes__default.default.bool.isRequired,readOnly:PropTypes__default.default.bool.isRequired,answerableCallback:PropTypes__default.default.func,getAnotherHint:PropTypes__default.default.func,interactionCallback:PropTypes__default.default.func,imagePlaceholder:PropTypes__default.default.node,widgetPlaceholder:PropTypes__default.default.node,baseElements:PropTypes__default.default.shape({Link:PropTypes__default.default.func}),trackInteraction:PropTypes__default.default.func,customKeypad:PropTypes__default.default.bool,isMobile:PropTypes__default.default.bool,isMobileApp:PropTypes__default.default.bool,hintProgressColor:PropTypes__default.default.string}).isRequired,defaults:{isArticle:false,isMobile:false,isMobileApp:false,editingDisabled:false,onFocusChange:function(){},showAlignmentOptions:false,readOnly:false,baseElements:{Link:props=>{const{children,...rest}=props;return jsxRuntimeExports.jsx("a",{...rest,children:children})}}}};const ClassNames={RENDERER:"perseus-renderer",TWO_COLUMN_RENDERER:"perseus-renderer-two-columns",RESPONSIVE_RENDERER:"perseus-renderer-responsive",INPUT:"perseus-input",FOCUSED:"perseus-focused",MOBILE:"perseus-mobile"};
1483
1483
 
1484
1484
  const getPromptJSON$r=(label,userInput)=>{return {type:"expression",label,userInput:{value:userInput}}};
1485
1485
 
1486
- const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};const defaultButtonSets=["basic","trig","prealgebra","logarithms"];const defaultOnFocus=()=>{};const defaultOnBlur=()=>{};const KeypadInputWithInterface=React__namespace.forwardRef(function KeypadInputWithInterface(props,ref){const keypadInputRef=React__namespace.useRef(null);const noopKeypadActivation=_keypadActive=>{};React__namespace.useImperativeHandle(ref,()=>({focus:(cb=noopKeypadActivation)=>keypadInputRef.current?.focus(cb),blur:()=>keypadInputRef.current?.blur(),insert:val=>{keypadInputRef.current?.mathField?.pressKey?.(val);}}));return jsxRuntimeExports.jsx(mathInput.KeypadInput,{ref:keypadInputRef,...props})});const Expression=React.forwardRef(function Expression({apiOptions=ApiOptions.defaults,buttonSets=defaultButtonSets,times=false,onFocus=defaultOnFocus,onBlur=defaultOnBlur,userInput="",visibleLabel,ariaLabel,keypadElement,extraKeys,handleUserInput,trackInteraction,widgetId,answerForms,...rest},ref){const{strings}=usePerseusI18n();const{analytics}=useDependencies();const{setKeypadActive}=React__namespace.useContext(keypadContext.KeypadContext);const textareaId=React.useId();const inputRef=React.useRef(null);const rootRef=React.useRef(null);React.useEffect(()=>{analytics?.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"expression",widgetId}});if(rootRef.current){const isMobile=apiOptions.customKeypad;const selector=isMobile?".mq-textarea > span":"textarea";const inputElement=rootRef.current.querySelector(selector);if(inputElement instanceof HTMLElement){inputElement.setAttribute("id",textareaId);}}},[]);const handleFocus=()=>{analytics?.onAnalyticsEvent({type:"perseus:expression-focused",payload:null});onFocus([]);};const handleBlur=()=>{onBlur([]);};const changeAndTrack=(value,cb)=>{const normalized=normalizeTex(value);handleUserInput(normalized,cb);trackInteraction();};const mobileHandleFocus=()=>{keypadElement?.configure(getKeypadConfiguration(),()=>{if(rootRef.current){handleFocus();}});};const getKeypadConfiguration=React.useCallback(()=>{return {keypadType:"EXPRESSION",extraKeys:extraKeys,times:times}},[extraKeys,times]);const getFocusTarget=React.useCallback(()=>{if(!rootRef.current){return null}const isMobile=apiOptions.customKeypad;const selector=isMobile?".mq-textarea > span":"textarea";const element=rootRef.current.querySelector(selector);return element instanceof HTMLElement?element:null},[apiOptions.customKeypad]);React.useImperativeHandle(ref,()=>({focus:()=>{const targetBefore=getFocusTarget();inputRef.current?.focus?.(setKeypadActive);const targetAfter=getFocusTarget()??targetBefore??(document.activeElement instanceof HTMLElement?document.activeElement:null);if(!targetAfter){return false}if(document.activeElement!==targetAfter){targetAfter.focus();}return document.activeElement===targetAfter},focusInputPath:path=>{inputRef.current?.focus?.(setKeypadActive);},blurInputPath:path=>{if(typeof inputRef.current?.blur==="function"){inputRef.current?.blur();}},insert:keyPressed=>{inputRef.current?.insert?.(keyPressed);},getInputPaths:()=>[[]],getUserInput:()=>{return normalizeTex(userInput)},getKeypadConfiguration,getPromptJSON:()=>{return getPromptJSON$r(visibleLabel,normalizeTex(userInput))},getSerializedState:()=>{return {...rest,value:userInput,keypadConfiguration:getKeypadConfiguration(),times,buttonSets}}}),[userInput,setKeypadActive,getKeypadConfiguration,getFocusTarget,rest,visibleLabel,buttonSets,times]);const keypadConfiguration=getKeypadConfiguration();if(apiOptions.customKeypad){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{ref:rootRef,style:styles$C.mobileLabelInputWrapper,children:[!!visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",htmlFor:textareaId,tag:"label",children:visibleLabel}),jsxRuntimeExports.jsx(KeypadInputWithInterface,{ref:inputRef,ariaLabel:ariaLabel||strings.mathInputBox,value:userInput,keypadElement:keypadElement,onChange:changeAndTrack,onFocus:mobileHandleFocus,onBlur:handleBlur})]})}return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{ref:rootRef,style:styles$C.desktopLabelInputWrapper,children:[!!visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",htmlFor:textareaId,tag:"label",children:visibleLabel}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-expression",children:jsxRuntimeExports.jsx(MathInput,{ref:inputRef,value:userInput,onChange:changeAndTrack,convertDotToTimes:times,buttonSets:buttonSets,onFocus:handleFocus,onBlur:handleBlur,ariaLabel:ariaLabel||strings.mathInputBox,extraKeys:keypadConfiguration.extraKeys,onAnalyticsEvent:analytics?.onAnalyticsEvent??(async()=>{})})})]})});const styles$C=aphrodite.StyleSheet.create({mobileLabelInputWrapper:{padding:"15px 4px 0"},desktopLabelInputWrapper:{margin:"5px 5px 0"}});function getUserInputFromSerializedState$i(serializedState){return normalizeTex(serializedState.value)}function getStartUserInput$j(){return ""}function getOneCorrectAnswerFromRubric$1(rubric){const correctAnswers=(rubric.answerForms||[]).filter(answerForm=>answerForm.considered==="correct");if(correctAnswers.length===0){return}return correctAnswers[0].value}function getCorrectUserInput$a(options){for(const form of options.answerForms){if(form.considered==="correct"){return form.value}}return ""}var Expression$1 = {name:"expression",displayName:"Expression / Equation",widget:Expression,version:perseusCore.expressionLogic.version,isLintable:true,getOneCorrectAnswerFromRubric: getOneCorrectAnswerFromRubric$1,getStartUserInput: getStartUserInput$j,getCorrectUserInput: getCorrectUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$i};
1486
+ const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};const defaultButtonSets=["basic","trig","prealgebra","logarithms"];const defaultOnFocus=()=>{};const defaultOnBlur=()=>{};const KeypadInputWithInterface=React__namespace.forwardRef(function KeypadInputWithInterface(props,ref){const keypadInputRef=React__namespace.useRef(null);const noopKeypadActivation=_keypadActive=>{};React__namespace.useImperativeHandle(ref,()=>({focus:(cb=noopKeypadActivation)=>keypadInputRef.current?.focus(cb),blur:()=>keypadInputRef.current?.blur(),insert:val=>{keypadInputRef.current?.mathField?.pressKey?.(val);}}));return jsxRuntimeExports.jsx(mathInput.KeypadInput,{ref:keypadInputRef,...props})});const Expression=React.forwardRef(function Expression({apiOptions=ApiOptions.defaults,buttonSets=defaultButtonSets,times=false,onFocus=defaultOnFocus,onBlur=defaultOnBlur,userInput="",visibleLabel,ariaLabel,keypadElement,extraKeys,handleUserInput,trackInteraction,widgetId,answerForms,...rest},ref){const{strings}=usePerseusI18n();const{analytics}=useDependencies();const{setKeypadActive}=React__namespace.useContext(keypadContext.KeypadContext);const textareaId=React.useId();const inputRef=React.useRef(null);const rootRef=React.useRef(null);React.useEffect(()=>{analytics?.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"expression",widgetId}});if(rootRef.current){const isMobile=apiOptions.customKeypad;const selector=isMobile?".mq-textarea > span":"textarea";const inputElement=rootRef.current.querySelector(selector);if(inputElement instanceof HTMLElement){inputElement.setAttribute("id",textareaId);}}},[]);const handleFocus=()=>{analytics?.onAnalyticsEvent({type:"perseus:expression-focused",payload:null});onFocus([]);};const handleBlur=()=>{onBlur([]);};const changeAndTrack=(value,cb)=>{const normalized=normalizeTex(value);handleUserInput(normalized,cb);trackInteraction();};const mobileHandleFocus=()=>{keypadElement?.configure(getKeypadConfiguration(),()=>{if(rootRef.current){handleFocus();}});};const getKeypadConfiguration=React.useCallback(()=>{return {keypadType:"EXPRESSION",extraKeys:extraKeys,times:times}},[extraKeys,times]);const getFocusTarget=React.useCallback(()=>{if(!rootRef.current){return null}const isMobile=apiOptions.customKeypad;const selector=isMobile?".mq-textarea > span":"textarea";const element=rootRef.current.querySelector(selector);return element instanceof HTMLElement?element:null},[apiOptions.customKeypad]);React.useImperativeHandle(ref,()=>({focus:()=>{const targetBefore=getFocusTarget();inputRef.current?.focus?.(setKeypadActive);const targetAfter=getFocusTarget()??targetBefore??(document.activeElement instanceof HTMLElement?document.activeElement:null);if(!targetAfter){return false}if(document.activeElement!==targetAfter){targetAfter.focus();}return document.activeElement===targetAfter},focusInputPath:path=>{inputRef.current?.focus?.(setKeypadActive);},blurInputPath:path=>{if(typeof inputRef.current?.blur==="function"){inputRef.current?.blur();}},insert:keyPressed=>{inputRef.current?.insert?.(keyPressed);},getInputPaths:()=>[[]],getUserInput:()=>{return normalizeTex(userInput)},getKeypadConfiguration,getPromptJSON:()=>{return getPromptJSON$r(visibleLabel,normalizeTex(userInput))},getSerializedState:()=>{return {...rest,value:userInput,keypadConfiguration:getKeypadConfiguration(),times,buttonSets}}}),[userInput,setKeypadActive,getKeypadConfiguration,getFocusTarget,rest,visibleLabel,buttonSets,times]);const keypadConfiguration=getKeypadConfiguration();if(apiOptions.customKeypad){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{ref:rootRef,style:styles$D.mobileLabelInputWrapper,children:[!!visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",htmlFor:textareaId,tag:"label",children:visibleLabel}),jsxRuntimeExports.jsx(KeypadInputWithInterface,{ref:inputRef,ariaLabel:ariaLabel||strings.mathInputBox,value:userInput,keypadElement:keypadElement,onChange:changeAndTrack,onFocus:mobileHandleFocus,onBlur:handleBlur})]})}return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{ref:rootRef,style:styles$D.desktopLabelInputWrapper,children:[!!visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",htmlFor:textareaId,tag:"label",children:visibleLabel}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-expression",children:jsxRuntimeExports.jsx(MathInput,{ref:inputRef,value:userInput,onChange:changeAndTrack,convertDotToTimes:times,buttonSets:buttonSets,onFocus:handleFocus,onBlur:handleBlur,ariaLabel:ariaLabel||strings.mathInputBox,extraKeys:keypadConfiguration.extraKeys,onAnalyticsEvent:analytics?.onAnalyticsEvent??(async()=>{})})})]})});const styles$D=aphrodite.StyleSheet.create({mobileLabelInputWrapper:{padding:"15px 4px 0"},desktopLabelInputWrapper:{margin:"5px 5px 0"}});function getUserInputFromSerializedState$i(serializedState){return normalizeTex(serializedState.value)}function getStartUserInput$j(){return ""}function getOneCorrectAnswerFromRubric$1(rubric){const correctAnswers=(rubric.answerForms||[]).filter(answerForm=>answerForm.considered==="correct");if(correctAnswers.length===0){return}return correctAnswers[0].value}function getCorrectUserInput$a(options){for(const form of options.answerForms){if(form.considered==="correct"){return form.value}}return ""}var Expression$1 = {name:"expression",displayName:"Expression / Equation",widget:Expression,version:perseusCore.expressionLogic.version,isLintable:true,getOneCorrectAnswerFromRubric: getOneCorrectAnswerFromRubric$1,getStartUserInput: getStartUserInput$j,getCorrectUserInput: getCorrectUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$i};
1487
1487
 
1488
1488
  class SimpleKeypadInput extends React__namespace.Component{componentDidMount(){this._isMounted=true;}componentWillUnmount(){this._isMounted=false;}focus(){this.inputRef.current?.focus(this.context.setKeypadActive);}blur(){this.inputRef.current?.blur();}getValue(){return this.props.value}render(){const _this=this;const{keypadElement,onFocus,value,...rest}=_this.props;return jsxRuntimeExports.jsx(mathInput.KeypadInput,{ref:this.inputRef,keypadElement:keypadElement,onFocus:()=>{if(keypadElement){keypadElement.configure({keypadType:"FRACTION"},()=>{if(_this._isMounted){onFocus?.();}});}else {onFocus?.();}},value:value==null?"":""+value,...rest})}constructor(...args){super(...args),this._isMounted=false,this.inputRef=React__namespace.createRef();}}SimpleKeypadInput.contextType=keypadContext.KeypadContext;SimpleKeypadInput.propTypes={keypadElement:mathInput.keypadElementPropType,onFocus:PropTypes__default.default.func,value:PropTypes__default.default.oneOfType([PropTypes__default.default.string,PropTypes__default.default.number])};
1489
1489
 
@@ -1615,7 +1615,7 @@ const reactRootCache=new WeakMap;function render(element,container){const childr
1615
1615
 
1616
1616
  function findChildOrAdd(elem,className){const $child=$__default.default(elem).find("."+className);if($child.length===0){return $__default.default("<span>").addClass(className).appendTo($__default.default(elem))}return $child}var Tex$1 = {processMath:async function(elem,text,force,callback){const $elem=$__default.default(elem);if($elem.attr("data-math-formula")==null||force){const $texHolder=findChildOrAdd($elem,"tex-holder");if(text==null&&$elem.attr("data-math-formula")){text=$elem.attr("data-math-formula");}text=text!=null?text+"":"";text=kmath.KhanMath.cleanMath(text);$elem.attr("data-math-formula",text);const{TeX}=await getDependencies();render(React__namespace.createElement(TeX,{children:text,onRender:callback}),$texHolder[0]);}}};
1617
1617
 
1618
- const{processMath: processMath$1}=Tex$1;function polar$2(r,th){if(typeof r==="number"){r=[r,r];}th=th*Math.PI/180;return [r[0]*Math.cos(th),r[1]*Math.sin(th)]}var _bounds=/*#__PURE__*/_class_private_field_loose_key("_bounds"),_drawingTransform=/*#__PURE__*/_class_private_field_loose_key("_drawingTransform"),_labelElements=/*#__PURE__*/_class_private_field_loose_key("_labelElements"),_resizeObserver=/*#__PURE__*/_class_private_field_loose_key("_resizeObserver");let Graphie$1 = class Graphie{init(options){let scale=options.scale||[40,40];scale=typeof scale==="number"?[scale,scale]:scale;if(options.range==null){throw new perseusCore.PerseusError("range should be specified in graph init",perseusCore.Errors.Internal)}_class_private_field_loose_base(this,_bounds)[_bounds]=new GraphBounds(...options.range);_class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]=new DrawingTransform(this.raphael,scale,this.bounds());const[w,h]=this.drawingTransform().canvasDimensions();$__default.default(this.el).css({width:w,height:h});this.range=options.range;this.scale=scale;this.dimensions=[w,h];this.xpixels=w;this.ypixels=h;this.isMobile=options.isMobile??false;return this}graphInit(options){options=options||{};for(const[prop,val]of wonderStuffCore.entries(options)){if(!prop.match(/.*Opacity$/)&&prop!=="range"&&typeof val==="number"){options[prop]=[val,val];}if(prop==="range"||prop==="gridRange"){options[prop]=normalizeRange(options[prop]);}}const range=normalizeRange(options.range||[[-10,10],[-10,10]]);const gridRange=normalizeRange(options.gridRange||range);const scale=options.scale||[20,20];const grid=options.grid!=null?options.grid:true;const gridOpacity=options.gridOpacity||.1;const gridStep=toPair(options.gridStep||[1,1]);const axes=options.axes!=null?options.axes:true;const axisArrows=options.axisArrows||"";const axisOpacity=options.axisOpacity||1;const axisCenter=options.axisCenter||[Math.min(Math.max(range[0][0],0),range[0][1]),Math.min(Math.max(range[1][0],0),range[1][1])];const axisLabels=options.axisLabels!=null?options.axisLabels:false;const ticks=options.ticks!=null?options.ticks:true;const tickStep=options.tickStep||[2,2];const tickLen=options.tickLen||[5,5];const tickOpacity=options.tickOpacity||1;const labels=options.labels||options.labelStep||false;const labelStep=options.labelStep||[1,1];const labelOpacity=options.labelOpacity||1;let unityLabels=options.unityLabels||false;const labelFormat=options.labelFormat||function(a){return a};let xLabelFormat=options.xLabelFormat||labelFormat;let yLabelFormat=options.yLabelFormat||labelFormat;const realRange=[[range[0][0]-(range[0][0]>0?1:0),range[0][1]+(range[0][1]<0?1:0)],[range[1][0]-(range[1][0]>0?1:0),range[1][1]+(range[1][1]<0?1:0)]];if(!Array.isArray(unityLabels)){unityLabels=[unityLabels,unityLabels];}const minusIgnorer=function(lf){return function(a){return (lf(a)+"").replace(/-(\d)/g,"\\llap{-}$1")}};xLabelFormat=minusIgnorer(xLabelFormat);yLabelFormat=minusIgnorer(yLabelFormat);this.init({range:realRange,scale:scale,isMobile:options.isMobile});if(grid){this.grid(gridRange[0],gridRange[1],{stroke:options.isMobile?KhanColors.GRAY_C:"#000000",opacity:options.isMobile?1:gridOpacity,step:gridStep,strokeWidth:options.isMobile?1:2});}if(axes){if(axisArrows==="<->"||axisArrows===true){const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:axisOpacity,strokeWidth:options.isMobile?1:2,arrows:"->"},function(){if(range[1][0]<0&&range[1][1]>0){thisGraphie.path([axisCenter,[gridRange[0][0],axisCenter[1]]]);thisGraphie.path([axisCenter,[gridRange[0][1],axisCenter[1]]]);}if(range[0][0]<0&&range[0][1]>0){thisGraphie.path([axisCenter,[axisCenter[0],gridRange[1][0]]]);thisGraphie.path([axisCenter,[axisCenter[0],gridRange[1][1]]]);}});}else if(axisArrows==="->"||axisArrows===""){const thisGraphie=this;this.style({stroke:"#000000",opacity:axisOpacity,strokeWidth:2,arrows:axisArrows},function(){thisGraphie.path([[gridRange[0][0],axisCenter[1]],[gridRange[0][1],axisCenter[1]]]);thisGraphie.path([[axisCenter[0],gridRange[1][0]],[axisCenter[0],gridRange[1][1]]]);});}if(axisLabels&&axisLabels.length===2){this.label([gridRange[0][1],axisCenter[1]],axisLabels[0],"right");this.label([axisCenter[0],gridRange[1][1]],axisLabels[1],"above");}}if(ticks){const halfWidthTicks=options.isMobile;const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:tickOpacity,strokeWidth:1},()=>{let step=gridStep[0]*tickStep[0];let len=tickLen[0]/scale[1];let start=gridRange[0][0];let stop=gridRange[0][1];if(range[1][0]<0&&range[1][1]>0){for(let x=step+axisCenter[0];x<=stop;x+=step){if(x<stop||!axisArrows){thisGraphie.line([x,-len+axisCenter[1]],[x,halfWidthTicks?0:len+axisCenter[1]]);}}for(let x=-step+axisCenter[0];x>=start;x-=step){if(x>start||!axisArrows){thisGraphie.line([x,-len+axisCenter[1]],[x,halfWidthTicks?0:len+axisCenter[1]]);}}}step=gridStep[1]*tickStep[1];len=tickLen[1]/scale[0];start=gridRange[1][0];stop=gridRange[1][1];if(range[0][0]<0&&range[0][1]>0){for(let y=step+axisCenter[1];y<=stop;y+=step){if(y<stop||!axisArrows){this.line([-len+axisCenter[0],y],[halfWidthTicks?0:len+axisCenter[0],y]);}}for(let y=-step+axisCenter[1];y>=start;y-=step){if(y>start||!axisArrows){this.line([-len+axisCenter[0],y],[halfWidthTicks?0:len+axisCenter[0],y]);}}}});}if(labels){const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:labelOpacity},function(){let step=gridStep[0]*tickStep[0]*labelStep[0];let start=gridRange[0][0];let stop=gridRange[0][1];const xAxisPosition=axisCenter[0]<0?"above":"below";const yAxisPosition=axisCenter[0]<0?"right":"left";const xShowZero=axisCenter[0]===0&&axisCenter[1]!==0;const yShowZero=axisCenter[0]!==0&&axisCenter[1]===0;const axisOffCenter=axisCenter[0]!==0||axisCenter[1]!==0;const showUnityX=unityLabels[0]||axisOffCenter;const showUnityY=unityLabels[1]||axisOffCenter;for(let x=(xShowZero?0:step)+axisCenter[0];x<=stop;x+=step){if(x<stop||!axisArrows){thisGraphie.label([x,axisCenter[1]],xLabelFormat(x),xAxisPosition);}}for(let x=-step*(showUnityX?1:2)+axisCenter[0];x>=start;x-=step){if(x>start||!axisArrows){thisGraphie.label([x,axisCenter[1]],xLabelFormat(x),xAxisPosition);}}step=gridStep[1]*tickStep[1]*labelStep[1];start=gridRange[1][0];stop=gridRange[1][1];for(let y=(yShowZero?0:step)+axisCenter[1];y<=stop;y+=step){if(y<stop||!axisArrows){thisGraphie.label([axisCenter[0],y],yLabelFormat(y),yAxisPosition);}}for(let y=-step*(showUnityY?1:2)+axisCenter[1];y>=start;y-=step){if(y>start||!axisArrows){thisGraphie.label([axisCenter[0],y],yLabelFormat(y),yAxisPosition);}}});}}drawingTransform(){if(_class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]==null){throw new Error("Can't get drawingTransform of an uninitialized Graphie")}return _class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]}bounds(){if(_class_private_field_loose_base(this,_bounds)[_bounds]==null){throw new Error("Can't get bounds of an uninitialized Graphie")}return _class_private_field_loose_base(this,_bounds)[_bounds]}style(attrs,fn){const processed=this.processAttributes(attrs);if(typeof fn==="function"){const oldStyle=this.currentStyle;this.currentStyle={...this.currentStyle,...processed};const result=fn.call(this);this.currentStyle=oldStyle;return result}Object.assign(this.currentStyle,processed);}grid(xr,yr,style){return this.withStyle(style,()=>{const step=this.currentStyle.step||[1,1];const set=this.raphael.set();let x=step[0]*Math.ceil(xr[0]/step[0]);for(;x<=xr[1];x+=step[0]){set.push(this.line([x,yr[0]],[x,yr[1]]));}let y=step[1]*Math.ceil(yr[0]/step[1]);for(;y<=yr[1];y+=step[1]){set.push(this.line([xr[0],y],[xr[1],y]));}return set})}arc(center,radius,startAngle,endAngle,sector,style){return this.withStyle(style,()=>{startAngle=(startAngle%360+360)%360;endAngle=(endAngle%360+360)%360;const cent=this.scalePoint(center);const radii=this.scaleVector(radius);const startVector=polar$2(radius,startAngle);const endVector=polar$2(radius,endAngle);const round=x=>kmath.number.round(x,6);const startPoint=this.scalePoint([round(center[0]+startVector[0]),round(center[1]+startVector[1])]);const endPoint=this.scalePoint([round(center[0]+endVector[0]),round(center[1]+endVector[1])]);const largeAngle=((endAngle-startAngle)%360+360)%360>180;return this.raphael.path("M"+startPoint.join(" ")+"A"+radii.join(" ")+" 0 "+(largeAngle?1:0)+" 0 "+endPoint.join(" ")+(sector?"L"+cent.join(" ")+"z":""))})}circle(center,radius,style){return this.withStyle(style,()=>this.raphael.ellipse(...this.scalePoint(center),...this.scaleVector([radius,radius])))}rect(x,y,width,height,style){return this.withStyle(style,()=>{const corner=this.scalePoint([x,y+height]);const dims=this.scaleVector([width,height]);const elem=this.raphael.rect(...corner.concat(dims));if(this.isMobile){elem.node.style.shapeRendering="crispEdges";}return elem})}ellipse(center,radii,style){return this.withStyle(style,()=>this.raphael.ellipse(...this.scalePoint(center).concat(this.scaleVector(radii))))}fixedEllipse(center,radii,maxScale,padding,style){return this.withStyle(style,()=>{const scaledPoint=this.scalePoint(center);const scaledRadii=this.scaleVector(radii);const width=2*scaledRadii[0]*maxScale+padding;const height=2*scaledRadii[1]*maxScale+padding;const left=scaledPoint[0]-width/2;const top=scaledPoint[1]-height/2;const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px"});const localRaphael=Raphael$1(wrapper,width,height);const visibleShape=localRaphael.ellipse(width/2,height/2,scaledRadii[0],scaledRadii[1]);return {wrapper:wrapper,visibleShape:visibleShape}})}unstyledPath(points){const p=this.raphael.path(this.svgPath(points));p.graphiePath=points;return p}path(points,style){return this.withStyle(style,()=>{return this.unstyledPath(points)})}fixedPath(points,center,createPath){points=points.map(this.scalePoint);center=center?this.scalePoint(center):null;createPath=createPath||this.svgPath;const xs=points.map(p=>p[0]);const ys=points.map(p=>p[1]);const pathLeft=Math.min(...xs);const pathRight=Math.max(...xs);const pathTop=Math.min(...ys);const pathBottom=Math.max(...ys);const padding=[4,4];const topLeftOfBoundingBox=[pathLeft,pathTop];points=points.map(function(point){return kmath.vector.add(kmath.vector.subtract(point,topLeftOfBoundingBox),kmath.vector.scale(padding,.5))});const width=pathRight-pathLeft+padding[0];const height=pathBottom-pathTop+padding[1];const left=topLeftOfBoundingBox[0]-padding[0]/2;const top=topLeftOfBoundingBox[1]-padding[1]/2;const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px",transformOrigin:center?width/2+center[0]+"px "+(height/2+center[1])+"px":null});const localRaphael=Raphael$1(wrapper,width,height);const visibleShape=localRaphael.path(createPath(points));return {wrapper:wrapper,visibleShape:visibleShape}}scaledPath(points,style){return this.withStyle(style,()=>{const p=this.raphael.path(this.svgPath(points,true));p.graphiePath=points;return p})}line(start,end,style){return this.withStyle(style,()=>{const l=this.unstyledPath([start,end]);if(this.isMobile){l.node.style.shapeRendering="crispEdges";}return l})}parabola(a,b,c,style){return this.withStyle(style,()=>this.raphael.path(this.svgParabolaPath(a,b,c)))}fixedLine(start,end,thickness){const padding=[thickness,thickness];start=this.scalePoint(start);end=this.scalePoint(end);const extraOffset=[Math.min(start[0],end[0]),Math.min(start[1],end[1])];start=kmath.vector.add(kmath.vector.subtract(start,extraOffset),kmath.vector.scale(padding,.5));end=kmath.vector.add(kmath.vector.subtract(end,extraOffset),kmath.vector.scale(padding,.5));const left=extraOffset[0]-padding[0]/2;const top=extraOffset[1]-padding[1]/2;const width=Math.abs(start[0]-end[0])+padding[0];const height=Math.abs(start[1]-end[1])+padding[1];const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px",transformOrigin:start[0]+"px "+start[1]+"px"});const localRaphael=Raphael$1(wrapper,width,height);const path="M"+start[0]+" "+start[1]+" "+"L"+end[0]+" "+end[1];const visibleShape=localRaphael.path(path);visibleShape.graphiePath=[start,end];return {wrapper:wrapper,visibleShape:visibleShape}}sinusoid(a,b,c,d,style){return this.withStyle(style,()=>this.raphael.path(this.svgSinusoidPath(a,b,c,d)))}plotParametric(fn,range,style){return this.withStyle(style,()=>{const clip=xy=>{if(Math.abs(xy[1])>5e5){return [xy[0],Math.min(Math.max(xy[1],-5e5),5e5)]}return xy};const clippedFn=x=>clip(fn(x));const min=range[0];const max=range[1];let step=(max-min)/(this.currentStyle["plot-points"]||800);if(step===0){step=1;}const paths=this.raphael.set();let points=[];let lastY=clippedFn(min)[1];for(let t=min;t<=max;t+=step){const point=clippedFn(t);const y=point[1];if(y>0!==lastY>0&&Math.abs(y-lastY)>2*this.drawingTransform().pixelsPerUnitY()||isNaN(y)){paths.push(this.unstyledPath(points));points=[];}else {points.push(point);}lastY=y;}paths.push(this.unstyledPath(points));return paths})}plot(fn,range,style){return this.withStyle(style,()=>{const min=range[0];const max=range[1];if(!this.currentStyle["plot-points"]){this.currentStyle["plot-points"]=2*(max-min)*this.drawingTransform().pixelsPerUnitX();}const parametricFn=x=>[x,fn(x)];return this.plotParametric(parametricFn,range)})}withStyle(style,fn){const oldStyle=this.currentStyle;this.currentStyle={...this.currentStyle,...this.processAttributes(style)};const result=this.postprocessDrawingResult(fn());this.currentStyle=oldStyle;return result}postprocessDrawingResult(result){const type=result.constructor.prototype;if(type===Raphael$1.el||type===Raphael$1.st){result.attr(this.currentStyle);if(this.currentStyle.arrows){result=this.addArrowheads(result);}}else if(result instanceof $__default.default){result.css({...this.currentStyle,...SVG_SPECIFIC_STYLE_MASK});}return result}addArrowheads(path){const type=path.constructor.prototype;if(type===Raphael$1.el){if(path.type==="path"&&typeof path.arrowheadsDrawn==="undefined"){const w=path.attr("stroke-width");const s=.6+.4*w;const l=path.getTotalLength();const set=this.raphael.set();const head=this.raphael.path(this.isMobile?"M-4,4 C-4,4 -0.25,0 -0.25,0 C-0.25,0 -4,-4 -4,-4":"M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4");const end=path.getPointAtLength(l-.4);const almostTheEnd=path.getPointAtLength(l-.75*s);const angle=Math.atan2(end.y-almostTheEnd.y,end.x-almostTheEnd.x)*180/Math.PI;const attrs=path.attr();delete attrs.path;let subpath=path.getSubpath(0,l-.75*s);subpath=this.raphael.path(subpath).attr(attrs);subpath.arrowheadsDrawn=true;path.remove();head.rotate(angle,this.isMobile?1e-5:.75,0).scale(s,s,.75,0).translate(almostTheEnd.x,almostTheEnd.y).attr(attrs).attr({"stroke-linejoin":"round","stroke-linecap":"round"});head.arrowheadsDrawn=true;set.push(subpath);set.push(head);return set}}else if(type===Raphael$1.st){for(let i=0,l=path.items.length;i<l;i++){this.addArrowheads(path.items[i]);}}return path}processAttributes(attrs){const transformers={scale:scale=>{this.drawingTransform().setScale(scale);},clipRect:pair=>{const point=pair[0];const size=pair[1];point[1]+=size[1];return {"clip-rect":this.scalePoint(point).concat(this.scaleVector(size)).join(" ")}},strokeWidth:function(val){return {"stroke-width":parseFloat(val)}},rx:val=>{return {rx:this.scaleVector([val,0])[0]}},ry:val=>{return {ry:this.scaleVector([0,val])[1]}},r:val=>{const scaled=this.scaleVector([val,val]);return {rx:scaled[0],ry:scaled[1]}}};const processed={};Object.entries(attrs||{}).forEach(function([key,value]){const transformer=transformers[key];if(typeof transformer==="function"){Object.assign(processed,transformer(value));}else {const dasherized=String(key).replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").replace(/([a-z\d])([A-Z])/g,"$1-$2").toLowerCase();processed[dasherized]=value;}});return processed}addMouseLayer(options){const localOptions={allowScratchpad:false,setDrawingAreaAvailable:function(){},...options};const mouselayerZIndex=2;this.mouselayer=Raphael$1(this.el,this.xpixels,this.ypixels);$__default.default(this.mouselayer.canvas).css("z-index",mouselayerZIndex);if(localOptions.onClick||localOptions.onMouseDown||localOptions.onMouseMove||localOptions.onMouseOver||localOptions.onMouseOut){const canvasClickTarget=this.mouselayer.rect(0,0,this.xpixels,this.ypixels).attr({fill:"#000",opacity:0});let isClickingCanvas=false;$__default.default(this.mouselayer.canvas).on("vmousedown",e=>{if(e.target===canvasClickTarget[0]){if(localOptions.onMouseDown){localOptions.onMouseDown(this.getMouseCoord(e));}isClickingCanvas=true;if(localOptions.onMouseMove){const handler=localOptions.onMouseMove;$__default.default(document).bind("vmousemove.mouseLayer",e=>{if(isClickingCanvas){e.preventDefault();handler(this.getMouseCoord(e));}});}$__default.default(document).bind("vmouseup.mouseLayer",e=>{$__default.default(document).unbind(".mouseLayer");if(isClickingCanvas&&localOptions.onClick){localOptions.onClick(this.getMouseCoord(e));}isClickingCanvas=false;});}});if(localOptions.onMouseOver){const handler=localOptions.onMouseOver;$__default.default(this.mouselayer.canvas).on("vmouseover",e=>{handler(this.getMouseCoord(e));});}if(localOptions.onMouseOut){const handler=localOptions.onMouseOut;$__default.default(this.mouselayer.canvas).on("vmouseout",e=>{handler(this.getMouseCoord(e));});}}if(!localOptions.allowScratchpad){localOptions.setDrawingAreaAvailable?.(false);}this._mouselayerWrapper=document.createElement("div");$__default.default(this._mouselayerWrapper).css({position:"absolute",left:0,top:0,zIndex:mouselayerZIndex});this._visiblelayerWrapper=document.createElement("div");$__default.default(this._visiblelayerWrapper).css({position:"absolute",left:0,top:0});const el=this.el;el.appendChild(this._visiblelayerWrapper);el.appendChild(this._mouselayerWrapper);this.addToMouseLayerWrapper=el=>{this._mouselayerWrapper?.appendChild(el);};this.addToVisibleLayerWrapper=el=>{this._visiblelayerWrapper?.appendChild(el);};}addToMouseLayerWrapper(el){throw new Error("addToMouseLayerWrapper is not ready. Call addMouseLayer() first.")}addToVisibleLayerWrapper(el){throw new Error("addToVisibleLayerWrapper is not ready. Call addMouseLayer() first.")}getMousePx(event){const offset=$__default.default(this.el).offset();const mouseX=event.pageX-offset.left;const mouseY=event.pageY-offset.top;return [mouseX,mouseY]}getMouseCoord(event){return this.unscalePoint(this.getMousePx(event))}_ensureResizeObserver(){if(_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]!=null||typeof ResizeObserver==="undefined"){return}_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=new ResizeObserver(()=>{this._recalculateLabels();});_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver].observe(this.el);}_recalculateLabels(){_class_private_field_loose_base(this,_labelElements)[_labelElements].forEach(span=>{const originalSize=$__default.default(span).data("originalLabelSize");if(originalSize!=null){setLabelMargins(span,originalSize);}});}cleanup(){_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]?.disconnect();_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=null;_class_private_field_loose_base(this,_labelElements)[_labelElements].clear();}constructor(el){Object.defineProperty(this,_bounds,{writable:true,value:void 0});Object.defineProperty(this,_drawingTransform,{writable:true,value:void 0});Object.defineProperty(this,_labelElements,{writable:true,value:void 0});Object.defineProperty(this,_resizeObserver,{writable:true,value:void 0});_class_private_field_loose_base(this,_labelElements)[_labelElements]=new Set;_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=null;this.isMobile=false;this.currentStyle={"stroke-width":2,fill:"none"};this.label=(point,text,direction,arg4,arg5)=>{const style=typeof arg4==="object"?arg4:arg5;const latex=typeof arg4==="boolean"?arg4:true;return this.withStyle(style,()=>{const $span=$__default.default("<span>").addClass("graphie-label");const pad=this.currentStyle["label-distance"];$span.css({position:"absolute",padding:(pad!=null?pad:7)+"px",color:"black"}).data("labelDirection",direction).appendTo(this.el);$span.setPosition=point=>{const scaledPoint=this.scalePoint(point);$span.css({left:scaledPoint[0],top:scaledPoint[1]});};$span.setPosition(point);$span.css({"font-size":this.currentStyle["font-size"]});const span=$span[0];_class_private_field_loose_base(this,_labelElements)[_labelElements].add(span);$span.processMath=function(math,force){processMath$1(span,math,force,function(){const width=span.scrollWidth;const height=span.scrollHeight;setLabelMargins(span,[width,height]);});};$span.processText=function(text){$span.html(text);const width=span.scrollWidth;const height=span.scrollHeight;setLabelMargins(span,[width,height]);};if(latex){$span.processMath(text,false);}else {$span.processText(text);}this._ensureResizeObserver();return $span})};this.svgPath=(points,alreadyScaled)=>{return points.map((point,i)=>{if(point===true){return "z"}const scaled=alreadyScaled?point:this.scalePoint(point);return (i===0?"M":"L")+kmath.KhanMath.bound(scaled[0])+" "+kmath.KhanMath.bound(scaled[1])}).join("")};this.svgParabolaPath=(a,b,c)=>{const computeParabola=function(x){return (a*x+b)*x+c};if(a===0){const points=[[this.bounds().xMin,computeParabola(this.bounds().xMin)],[this.bounds().xMax,computeParabola(this.bounds().xMax)]];return this.svgPath(points)}const xVertex=-b/(2*a);const distToEdge=Math.max(Math.abs(xVertex-this.bounds().xMin),Math.abs(xVertex-this.bounds().xMax));const xPoint=xVertex+distToEdge;const vertex=[xVertex,computeParabola(xVertex)];const point=[xPoint,computeParabola(xPoint)];const control=[vertex[0],vertex[1]-(point[1]-vertex[1])];const dx=Math.abs(vertex[0]-point[0]);const left=[vertex[0]-dx,point[1]];const right=[vertex[0]+dx,point[1]];const points=[left,control,right].map(this.scalePoint);const values=points.flat().map(kmath.KhanMath.bound);return "M"+values[0]+","+values[1]+" Q"+values[2]+","+values[3]+" "+values[4]+","+values[5]};this.svgSinusoidPath=(a,b,c,d)=>{const quarterPeriod=Math.abs(Math.PI/(2*b));const computeSine=function(x){return a*Math.sin(b*x-c)+d};const computeDerivative=function(x){return a*b*Math.cos(c-b*x)};const coordsForOffset=(initial,i)=>{const x0=initial+quarterPeriod*i;const x1=x0+quarterPeriod;const xCoords=[x0,x0*2/3+x1*1/3,x0*1/3+x1*2/3,x1];const yCoords=[computeSine(x0),computeSine(x0)+computeDerivative(x0)*(x1-x0)/3,computeSine(x1)-computeDerivative(x1)*(x1-x0)/3,computeSine(x1)];const points=kmath.vector.zip(xCoords,yCoords);return points.map(this.scalePoint)};const extent=this.bounds().width();const numQuarterPeriods=Math.ceil(extent/quarterPeriod)+1;let initial=c/b;const distToEdge=initial-this.bounds().xMin;initial-=quarterPeriod*Math.ceil(distToEdge/quarterPeriod);let coords=coordsForOffset(initial,0);let path="M"+coords[0][0]+","+coords[0][1]+" C"+coords[1][0]+","+coords[1][1]+" "+coords[2][0]+","+coords[2][1]+" "+coords[3][0]+","+coords[3][1];for(let i=1;i<numQuarterPeriods;i++){coords=coordsForOffset(initial,i);path+=" C"+coords[1][0]+","+coords[1][1]+" "+coords[2][0]+","+coords[2][1]+" "+coords[3][0]+","+coords[3][1];}return path};this.scalePoint=point=>{return this.drawingTransform().scalePoint(point)};this.scaleVector=point=>{return this.drawingTransform().scaleVector(point)};this.unscalePoint=point=>{return this.drawingTransform().unscalePoint(point)};this.unscaleVector=point=>{return this.drawingTransform().unscaleVector(point)};this.el=el;$__default.default(el).css("position","relative");this.raphael=Raphael$1(el);$__default.default(el).attr("aria-hidden","true");$__default.default(el).children("div").css("position","absolute");}};const labelDirections={center:[-0.5,-0.5],above:[-0.5,-1],"above right":[0,-1],right:[0,-0.5],"below right":[0,0],below:[-0.5,0],"below left":[-1,0],left:[-1,-0.5],"above left":[-1,-1]};function normalizeRange(range){function normalizeInterval(magnitude){if(typeof magnitude==="number"){return [-magnitude,magnitude]}else {return magnitude}}function getXAndYRanges(range){if(Array.isArray(range)){return range}else {return [range,range]}}if(range==null){return range}const[xRange,yRange]=getXAndYRanges(range);return [normalizeInterval(xRange),normalizeInterval(yRange)]}function toPair(x){if(Array.isArray(x)){return x}return [x,x]}const SVG_SPECIFIC_STYLE_MASK={"stroke-width":null};const setLabelMargins=function(span,size){if(document.fonts?.status==="loading"){document.fonts.ready.then(()=>setLabelMargins(span,size));return}const $span=$__default.default(span);const direction=$span.data("labelDirection");let[width,height]=size;if(width===0&&height===0){[width,height]=[1,1];Log.log("Label size was 0x0 in graphie.js; using 1x1 instead");}$span.css("visibility","");if(typeof direction==="number"){const x=Math.cos(direction);const y=Math.sin(direction);const scale=Math.min(width/2/Math.abs(x),height/2/Math.abs(y));$span.css({marginLeft:-width/2+x*scale,marginTop:-height/2-y*scale});if($span.data("originalLabelSize")==null){$span.data("originalLabelSize",[width,height]);}}else {const $svgImage=$span.closest(".svg-image");const $graphie=$span.closest(".graphie");const $container=$svgImage.length>0?$svgImage:$graphie;$container.css("line-height","normal");if($span.data("originalLabelSize")==null){height=span.scrollHeight;$span.data("originalLabelSize",[width,height]);}const widthValues=$container.css(["max-width","width"])??{"max-width":"0px"};const expectedWidth=widthValues["max-width"]!=="none"?widthValues["max-width"]:widthValues["width"];let scale=($container.width()??0)/parseInt(expectedWidth.replace(/px$/,""));if(isNaN(scale)){scale=1;}else if(scale===0){scale=1;}let rawPadding;const storedPadding=$span.data("originalPadding");if(storedPadding!=null){rawPadding=storedPadding;}else {const padding=$span.css("padding")??"0px";const currentPadding=padding!=="none"?padding:"0px";rawPadding=parseInt(currentPadding.replace(/px$/,""));$span.data("originalPadding",rawPadding);}let normalizedWidth=width;let normalizedHeight=height;const imageScale=Number($container.attr("data-scale"));const hasValidImageScale=!Number.isNaN(imageScale)&&imageScale>=0;if(hasValidImageScale){scale=scale*imageScale;const totalPadding=2*rawPadding;normalizedWidth=(width-totalPadding)/imageScale+totalPadding;normalizedHeight=(height-totalPadding)/imageScale+totalPadding;}const newPadding=rawPadding*scale;const multipliers=labelDirections[direction||"center"];const styling={marginLeft:normalizedWidth*multipliers[0]*scale,marginTop:normalizedHeight*multipliers[1]*scale,padding:`${newPadding}px`,fontSize:`${scale*100}%`};$span.css(styling);}};const GraphUtils={Graphie: Graphie$1,createGraphie:function(el){return new Graphie$1(el)},unscaledSvgPath:function(points){if(points[0]===true){return ""}return points.map(function(point,i){if(point===true){return "z"}return (i===0?"M":"L")+point[0]+" "+point[1]}).join("")},getDistance:function(point1,point2){return kmath.point.distanceToPoint(point1,point2)},findAngleDeprecated:function(point1,point2,vertex){if(vertex===undefined){const x=point1[0]-point2[0];const y=point1[1]-point2[1];if(!x&&!y){return 0}return (180+Math.atan2(-y,-x)*180/Math.PI+360)%360}return GraphUtils.findAngleDeprecated(point1,vertex)-GraphUtils.findAngleDeprecated(point2,vertex)},graphs:{}};
1618
+ const{processMath: processMath$1}=Tex$1;function polar$2(r,th){if(typeof r==="number"){r=[r,r];}th=th*Math.PI/180;return [r[0]*Math.cos(th),r[1]*Math.sin(th)]}var _bounds=/*#__PURE__*/_class_private_field_loose_key("_bounds"),_drawingTransform=/*#__PURE__*/_class_private_field_loose_key("_drawingTransform"),_labelElements=/*#__PURE__*/_class_private_field_loose_key("_labelElements"),_resizeObserver=/*#__PURE__*/_class_private_field_loose_key("_resizeObserver");let Graphie$1 = class Graphie{init(options){let scale=options.scale||[40,40];scale=typeof scale==="number"?[scale,scale]:scale;if(options.range==null){throw new perseusCore.PerseusError("range should be specified in graph init",perseusCore.Errors.Internal)}_class_private_field_loose_base(this,_bounds)[_bounds]=new GraphBounds(...options.range);_class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]=new DrawingTransform(this.raphael,scale,this.bounds());const[w,h]=this.drawingTransform().canvasDimensions();$__default.default(this.el).css({width:w,height:h});this.range=options.range;this.scale=scale;this.dimensions=[w,h];this.xpixels=w;this.ypixels=h;this.isMobile=options.isMobile??false;return this}graphInit(options){options=options||{};for(const[prop,val]of wonderStuffCore.entries(options)){if(!prop.match(/.*Opacity$/)&&prop!=="range"&&typeof val==="number"){options[prop]=[val,val];}if(prop==="range"||prop==="gridRange"){options[prop]=normalizeRange(options[prop]);}}const range=normalizeRange(options.range||[[-10,10],[-10,10]]);const gridRange=normalizeRange(options.gridRange||range);const scale=options.scale||[20,20];const grid=options.grid!=null?options.grid:true;const gridOpacity=options.gridOpacity||.1;const gridStep=toPair(options.gridStep||[1,1]);const axes=options.axes!=null?options.axes:true;const axisArrows=options.axisArrows||"";const axisOpacity=options.axisOpacity||1;const axisCenter=options.axisCenter||[Math.min(Math.max(range[0][0],0),range[0][1]),Math.min(Math.max(range[1][0],0),range[1][1])];const axisLabels=options.axisLabels!=null?options.axisLabels:false;const ticks=options.ticks!=null?options.ticks:true;const tickStep=options.tickStep||[2,2];const tickLen=options.tickLen||[5,5];const tickOpacity=options.tickOpacity||1;const labels=options.labels||options.labelStep||false;const labelStep=options.labelStep||[1,1];const labelOpacity=options.labelOpacity||1;let unityLabels=options.unityLabels||false;const labelFormat=options.labelFormat||function(a){return a};let xLabelFormat=options.xLabelFormat||labelFormat;let yLabelFormat=options.yLabelFormat||labelFormat;const realRange=[[range[0][0]-(range[0][0]>0?1:0),range[0][1]+(range[0][1]<0?1:0)],[range[1][0]-(range[1][0]>0?1:0),range[1][1]+(range[1][1]<0?1:0)]];if(!Array.isArray(unityLabels)){unityLabels=[unityLabels,unityLabels];}const minusIgnorer=function(lf){return function(a){return (lf(a)+"").replace(/-(\d)/g,"\\llap{-}$1")}};xLabelFormat=minusIgnorer(xLabelFormat);yLabelFormat=minusIgnorer(yLabelFormat);this.init({range:realRange,scale:scale,isMobile:options.isMobile});if(grid){this.grid(gridRange[0],gridRange[1],{stroke:options.isMobile?KhanColors.GRAY_C:"#000000",opacity:options.isMobile?1:gridOpacity,step:gridStep,strokeWidth:options.isMobile?1:2});}if(axes){if(axisArrows==="<->"||axisArrows===true){const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:axisOpacity,strokeWidth:options.isMobile?1:2,arrows:"->"},function(){if(range[1][0]<0&&range[1][1]>0){thisGraphie.path([axisCenter,[gridRange[0][0],axisCenter[1]]]);thisGraphie.path([axisCenter,[gridRange[0][1],axisCenter[1]]]);}if(range[0][0]<0&&range[0][1]>0){thisGraphie.path([axisCenter,[axisCenter[0],gridRange[1][0]]]);thisGraphie.path([axisCenter,[axisCenter[0],gridRange[1][1]]]);}});}else if(axisArrows==="->"||axisArrows===""){const thisGraphie=this;this.style({stroke:"#000000",opacity:axisOpacity,strokeWidth:2,arrows:axisArrows},function(){thisGraphie.path([[gridRange[0][0],axisCenter[1]],[gridRange[0][1],axisCenter[1]]]);thisGraphie.path([[axisCenter[0],gridRange[1][0]],[axisCenter[0],gridRange[1][1]]]);});}if(axisLabels&&axisLabels.length===2){this.label([gridRange[0][1],axisCenter[1]],axisLabels[0],"right");this.label([axisCenter[0],gridRange[1][1]],axisLabels[1],"above");}}if(ticks){const halfWidthTicks=options.isMobile;const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:tickOpacity,strokeWidth:1},()=>{let step=gridStep[0]*tickStep[0];let len=tickLen[0]/scale[1];let start=gridRange[0][0];let stop=gridRange[0][1];if(range[1][0]<0&&range[1][1]>0){for(let x=step+axisCenter[0];x<=stop;x+=step){if(x<stop||!axisArrows){thisGraphie.line([x,-len+axisCenter[1]],[x,halfWidthTicks?0:len+axisCenter[1]]);}}for(let x=-step+axisCenter[0];x>=start;x-=step){if(x>start||!axisArrows){thisGraphie.line([x,-len+axisCenter[1]],[x,halfWidthTicks?0:len+axisCenter[1]]);}}}step=gridStep[1]*tickStep[1];len=tickLen[1]/scale[0];start=gridRange[1][0];stop=gridRange[1][1];if(range[0][0]<0&&range[0][1]>0){for(let y=step+axisCenter[1];y<=stop;y+=step){if(y<stop||!axisArrows){this.line([-len+axisCenter[0],y],[halfWidthTicks?0:len+axisCenter[0],y]);}}for(let y=-step+axisCenter[1];y>=start;y-=step){if(y>start||!axisArrows){this.line([-len+axisCenter[0],y],[halfWidthTicks?0:len+axisCenter[0],y]);}}}});}if(labels){const thisGraphie=this;this.style({stroke:options.isMobile?KhanColors.GRAY_G:"#000000",opacity:options.isMobile?1:labelOpacity},function(){let step=gridStep[0]*tickStep[0]*labelStep[0];let start=gridRange[0][0];let stop=gridRange[0][1];const xAxisPosition=axisCenter[0]<0?"above":"below";const yAxisPosition=axisCenter[0]<0?"right":"left";const xShowZero=axisCenter[0]===0&&axisCenter[1]!==0;const yShowZero=axisCenter[0]!==0&&axisCenter[1]===0;const axisOffCenter=axisCenter[0]!==0||axisCenter[1]!==0;const showUnityX=unityLabels[0]||axisOffCenter;const showUnityY=unityLabels[1]||axisOffCenter;for(let x=(xShowZero?0:step)+axisCenter[0];x<=stop;x+=step){if(x<stop||!axisArrows){thisGraphie.label([x,axisCenter[1]],xLabelFormat(x),xAxisPosition);}}for(let x=-step*(showUnityX?1:2)+axisCenter[0];x>=start;x-=step){if(x>start||!axisArrows){thisGraphie.label([x,axisCenter[1]],xLabelFormat(x),xAxisPosition);}}step=gridStep[1]*tickStep[1]*labelStep[1];start=gridRange[1][0];stop=gridRange[1][1];for(let y=(yShowZero?0:step)+axisCenter[1];y<=stop;y+=step){if(y<stop||!axisArrows){thisGraphie.label([axisCenter[0],y],yLabelFormat(y),yAxisPosition);}}for(let y=-step*(showUnityY?1:2)+axisCenter[1];y>=start;y-=step){if(y>start||!axisArrows){thisGraphie.label([axisCenter[0],y],yLabelFormat(y),yAxisPosition);}}});}}drawingTransform(){if(_class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]==null){throw new Error("Can't get drawingTransform of an uninitialized Graphie")}return _class_private_field_loose_base(this,_drawingTransform)[_drawingTransform]}bounds(){if(_class_private_field_loose_base(this,_bounds)[_bounds]==null){throw new Error("Can't get bounds of an uninitialized Graphie")}return _class_private_field_loose_base(this,_bounds)[_bounds]}style(attrs,fn){const processed=this.processAttributes(attrs);if(typeof fn==="function"){const oldStyle=this.currentStyle;this.currentStyle={...this.currentStyle,...processed};const result=fn.call(this);this.currentStyle=oldStyle;return result}Object.assign(this.currentStyle,processed);}grid(xr,yr,style){return this.withStyle(style,()=>{const step=this.currentStyle.step||[1,1];const set=this.raphael.set();let x=step[0]*Math.ceil(xr[0]/step[0]);for(;x<=xr[1];x+=step[0]){set.push(this.line([x,yr[0]],[x,yr[1]]));}let y=step[1]*Math.ceil(yr[0]/step[1]);for(;y<=yr[1];y+=step[1]){set.push(this.line([xr[0],y],[xr[1],y]));}return set})}arc(center,radius,startAngle,endAngle,sector,style){return this.withStyle(style,()=>{startAngle=(startAngle%360+360)%360;endAngle=(endAngle%360+360)%360;const cent=this.scalePoint(center);const radii=this.scaleVector(radius);const startVector=polar$2(radius,startAngle);const endVector=polar$2(radius,endAngle);const round=x=>kmath.number.round(x,6);const startPoint=this.scalePoint([round(center[0]+startVector[0]),round(center[1]+startVector[1])]);const endPoint=this.scalePoint([round(center[0]+endVector[0]),round(center[1]+endVector[1])]);const largeAngle=((endAngle-startAngle)%360+360)%360>180;return this.raphael.path("M"+startPoint.join(" ")+"A"+radii.join(" ")+" 0 "+(largeAngle?1:0)+" 0 "+endPoint.join(" ")+(sector?"L"+cent.join(" ")+"z":""))})}circle(center,radius,style){return this.withStyle(style,()=>this.raphael.ellipse(...this.scalePoint(center),...this.scaleVector([radius,radius])))}rect(x,y,width,height,style){return this.withStyle(style,()=>{const corner=this.scalePoint([x,y+height]);const dims=this.scaleVector([width,height]);const elem=this.raphael.rect(...corner.concat(dims));if(this.isMobile){elem.node.style.shapeRendering="crispEdges";}return elem})}ellipse(center,radii,style){return this.withStyle(style,()=>this.raphael.ellipse(...this.scalePoint(center).concat(this.scaleVector(radii))))}fixedEllipse(center,radii,maxScale,padding,style){return this.withStyle(style,()=>{const scaledPoint=this.scalePoint(center);const scaledRadii=this.scaleVector(radii);const width=2*scaledRadii[0]*maxScale+padding;const height=2*scaledRadii[1]*maxScale+padding;const left=scaledPoint[0]-width/2;const top=scaledPoint[1]-height/2;const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px"});const localRaphael=Raphael$1(wrapper,width,height);const visibleShape=localRaphael.ellipse(width/2,height/2,scaledRadii[0],scaledRadii[1]);return {wrapper:wrapper,visibleShape:visibleShape}})}unstyledPath(points){const p=this.raphael.path(this.svgPath(points));p.graphiePath=points;return p}path(points,style){return this.withStyle(style,()=>{return this.unstyledPath(points)})}fixedPath(points,center,createPath){points=points.map(this.scalePoint);center=center?this.scalePoint(center):null;createPath=createPath||this.svgPath;const xs=points.map(p=>p[0]);const ys=points.map(p=>p[1]);const pathLeft=Math.min(...xs);const pathRight=Math.max(...xs);const pathTop=Math.min(...ys);const pathBottom=Math.max(...ys);const padding=[4,4];const topLeftOfBoundingBox=[pathLeft,pathTop];points=points.map(function(point){return kmath.vector.add(kmath.vector.subtract(point,topLeftOfBoundingBox),kmath.vector.scale(padding,.5))});const width=pathRight-pathLeft+padding[0];const height=pathBottom-pathTop+padding[1];const left=topLeftOfBoundingBox[0]-padding[0]/2;const top=topLeftOfBoundingBox[1]-padding[1]/2;const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px",transformOrigin:center?width/2+center[0]+"px "+(height/2+center[1])+"px":null});const localRaphael=Raphael$1(wrapper,width,height);const visibleShape=localRaphael.path(createPath(points));return {wrapper:wrapper,visibleShape:visibleShape}}scaledPath(points,style){return this.withStyle(style,()=>{const p=this.raphael.path(this.svgPath(points,true));p.graphiePath=points;return p})}line(start,end,style){return this.withStyle(style,()=>{const l=this.unstyledPath([start,end]);if(this.isMobile){l.node.style.shapeRendering="crispEdges";}return l})}parabola(a,b,c,style){return this.withStyle(style,()=>this.raphael.path(this.svgParabolaPath(a,b,c)))}fixedLine(start,end,thickness){const padding=[thickness,thickness];start=this.scalePoint(start);end=this.scalePoint(end);const extraOffset=[Math.min(start[0],end[0]),Math.min(start[1],end[1])];start=kmath.vector.add(kmath.vector.subtract(start,extraOffset),kmath.vector.scale(padding,.5));end=kmath.vector.add(kmath.vector.subtract(end,extraOffset),kmath.vector.scale(padding,.5));const left=extraOffset[0]-padding[0]/2;const top=extraOffset[1]-padding[1]/2;const width=Math.abs(start[0]-end[0])+padding[0];const height=Math.abs(start[1]-end[1])+padding[1];const wrapper=document.createElement("div");$__default.default(wrapper).css({position:"absolute",width:width+"px",height:height+"px",left:left+"px",top:top+"px",transformOrigin:start[0]+"px "+start[1]+"px"});const localRaphael=Raphael$1(wrapper,width,height);const path="M"+start[0]+" "+start[1]+" "+"L"+end[0]+" "+end[1];const visibleShape=localRaphael.path(path);visibleShape.graphiePath=[start,end];return {wrapper:wrapper,visibleShape:visibleShape}}sinusoid(a,b,c,d,style){return this.withStyle(style,()=>this.raphael.path(this.svgSinusoidPath(a,b,c,d)))}plotParametric(fn,range,style){return this.withStyle(style,()=>{const clip=xy=>{if(Math.abs(xy[1])>5e5){return [xy[0],Math.min(Math.max(xy[1],-5e5),5e5)]}return xy};const clippedFn=x=>clip(fn(x));const min=range[0];const max=range[1];let step=(max-min)/(this.currentStyle["plot-points"]||800);if(step===0){step=1;}const paths=this.raphael.set();let points=[];let lastY=clippedFn(min)[1];for(let t=min;t<=max;t+=step){const point=clippedFn(t);const y=point[1];if(y>0!==lastY>0&&Math.abs(y-lastY)>2*this.drawingTransform().pixelsPerUnitY()||isNaN(y)){paths.push(this.unstyledPath(points));points=[];}else {points.push(point);}lastY=y;}paths.push(this.unstyledPath(points));return paths})}plot(fn,range,style){return this.withStyle(style,()=>{const min=range[0];const max=range[1];if(!this.currentStyle["plot-points"]){this.currentStyle["plot-points"]=2*(max-min)*this.drawingTransform().pixelsPerUnitX();}const parametricFn=x=>[x,fn(x)];return this.plotParametric(parametricFn,range)})}withStyle(style,fn){const oldStyle=this.currentStyle;this.currentStyle={...this.currentStyle,...this.processAttributes(style)};const result=this.postprocessDrawingResult(fn());this.currentStyle=oldStyle;return result}postprocessDrawingResult(result){const type=result.constructor.prototype;if(type===Raphael$1.el||type===Raphael$1.st){result.attr(this.currentStyle);if(this.currentStyle.arrows){result=this.addArrowheads(result);}}else if(result instanceof $__default.default){result.css({...this.currentStyle,...SVG_SPECIFIC_STYLE_MASK});}return result}addArrowheads(path){const type=path.constructor.prototype;if(type===Raphael$1.el){if(path.type==="path"&&typeof path.arrowheadsDrawn==="undefined"){const w=path.attr("stroke-width");const s=.6+.4*w;const l=path.getTotalLength();const set=this.raphael.set();const head=this.raphael.path(this.isMobile?"M-4,4 C-4,4 -0.25,0 -0.25,0 C-0.25,0 -4,-4 -4,-4":"M-3 4 C-2.75 2.5 0 0.25 0.75 0C0 -0.25 -2.75 -2.5 -3 -4");const end=path.getPointAtLength(l-.4);const almostTheEnd=path.getPointAtLength(l-.75*s);const angle=Math.atan2(end.y-almostTheEnd.y,end.x-almostTheEnd.x)*180/Math.PI;const attrs=path.attr();delete attrs.path;let subpath=path.getSubpath(0,l-.75*s);subpath=this.raphael.path(subpath).attr(attrs);subpath.arrowheadsDrawn=true;path.remove();head.rotate(angle,this.isMobile?1e-5:.75,0).scale(s,s,.75,0).translate(almostTheEnd.x,almostTheEnd.y).attr(attrs).attr({"stroke-linejoin":"round","stroke-linecap":"round"});head.arrowheadsDrawn=true;set.push(subpath);set.push(head);return set}}else if(type===Raphael$1.st){for(let i=0,l=path.items.length;i<l;i++){this.addArrowheads(path.items[i]);}}return path}processAttributes(attrs){const transformers={scale:scale=>{this.drawingTransform().setScale(scale);},clipRect:pair=>{const point=pair[0];const size=pair[1];point[1]+=size[1];return {"clip-rect":this.scalePoint(point).concat(this.scaleVector(size)).join(" ")}},strokeWidth:function(val){return {"stroke-width":parseFloat(val)}},rx:val=>{return {rx:this.scaleVector([val,0])[0]}},ry:val=>{return {ry:this.scaleVector([0,val])[1]}},r:val=>{const scaled=this.scaleVector([val,val]);return {rx:scaled[0],ry:scaled[1]}}};const processed={};Object.entries(attrs||{}).forEach(function([key,value]){const transformer=transformers[key];if(typeof transformer==="function"){Object.assign(processed,transformer(value));}else {const dasherized=String(key).replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").replace(/([a-z\d])([A-Z])/g,"$1-$2").toLowerCase();processed[dasherized]=value;}});return processed}addMouseLayer(options){const localOptions={allowScratchpad:false,...options};const mouselayerZIndex=2;this.mouselayer=Raphael$1(this.el,this.xpixels,this.ypixels);$__default.default(this.mouselayer.canvas).css("z-index",mouselayerZIndex);if(localOptions.onClick||localOptions.onMouseDown||localOptions.onMouseMove||localOptions.onMouseOver||localOptions.onMouseOut){const canvasClickTarget=this.mouselayer.rect(0,0,this.xpixels,this.ypixels).attr({fill:"#000",opacity:0});let isClickingCanvas=false;$__default.default(this.mouselayer.canvas).on("vmousedown",e=>{if(e.target===canvasClickTarget[0]){if(localOptions.onMouseDown){localOptions.onMouseDown(this.getMouseCoord(e));}isClickingCanvas=true;if(localOptions.onMouseMove){const handler=localOptions.onMouseMove;$__default.default(document).bind("vmousemove.mouseLayer",e=>{if(isClickingCanvas){e.preventDefault();handler(this.getMouseCoord(e));}});}$__default.default(document).bind("vmouseup.mouseLayer",e=>{$__default.default(document).unbind(".mouseLayer");if(isClickingCanvas&&localOptions.onClick){localOptions.onClick(this.getMouseCoord(e));}isClickingCanvas=false;});}});if(localOptions.onMouseOver){const handler=localOptions.onMouseOver;$__default.default(this.mouselayer.canvas).on("vmouseover",e=>{handler(this.getMouseCoord(e));});}if(localOptions.onMouseOut){const handler=localOptions.onMouseOut;$__default.default(this.mouselayer.canvas).on("vmouseout",e=>{handler(this.getMouseCoord(e));});}}this._mouselayerWrapper=document.createElement("div");$__default.default(this._mouselayerWrapper).css({position:"absolute",left:0,top:0,zIndex:mouselayerZIndex});this._visiblelayerWrapper=document.createElement("div");$__default.default(this._visiblelayerWrapper).css({position:"absolute",left:0,top:0});const el=this.el;el.appendChild(this._visiblelayerWrapper);el.appendChild(this._mouselayerWrapper);this.addToMouseLayerWrapper=el=>{this._mouselayerWrapper?.appendChild(el);};this.addToVisibleLayerWrapper=el=>{this._visiblelayerWrapper?.appendChild(el);};}addToMouseLayerWrapper(el){throw new Error("addToMouseLayerWrapper is not ready. Call addMouseLayer() first.")}addToVisibleLayerWrapper(el){throw new Error("addToVisibleLayerWrapper is not ready. Call addMouseLayer() first.")}getMousePx(event){const offset=$__default.default(this.el).offset();const mouseX=event.pageX-offset.left;const mouseY=event.pageY-offset.top;return [mouseX,mouseY]}getMouseCoord(event){return this.unscalePoint(this.getMousePx(event))}_ensureResizeObserver(){if(_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]!=null||typeof ResizeObserver==="undefined"){return}_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=new ResizeObserver(()=>{this._recalculateLabels();});_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver].observe(this.el);}_recalculateLabels(){_class_private_field_loose_base(this,_labelElements)[_labelElements].forEach(span=>{const originalSize=$__default.default(span).data("originalLabelSize");if(originalSize!=null){setLabelMargins(span,originalSize);}});}cleanup(){_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]?.disconnect();_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=null;_class_private_field_loose_base(this,_labelElements)[_labelElements].clear();}constructor(el){Object.defineProperty(this,_bounds,{writable:true,value:void 0});Object.defineProperty(this,_drawingTransform,{writable:true,value:void 0});Object.defineProperty(this,_labelElements,{writable:true,value:void 0});Object.defineProperty(this,_resizeObserver,{writable:true,value:void 0});_class_private_field_loose_base(this,_labelElements)[_labelElements]=new Set;_class_private_field_loose_base(this,_resizeObserver)[_resizeObserver]=null;this.isMobile=false;this.currentStyle={"stroke-width":2,fill:"none"};this.label=(point,text,direction,arg4,arg5)=>{const style=typeof arg4==="object"?arg4:arg5;const latex=typeof arg4==="boolean"?arg4:true;return this.withStyle(style,()=>{const $span=$__default.default("<span>").addClass("graphie-label");const pad=this.currentStyle["label-distance"];$span.css({position:"absolute",padding:(pad!=null?pad:7)+"px",color:"black"}).data("labelDirection",direction).appendTo(this.el);$span.setPosition=point=>{const scaledPoint=this.scalePoint(point);$span.css({left:scaledPoint[0],top:scaledPoint[1]});};$span.setPosition(point);$span.css({"font-size":this.currentStyle["font-size"]});const span=$span[0];_class_private_field_loose_base(this,_labelElements)[_labelElements].add(span);$span.processMath=function(math,force){processMath$1(span,math,force,function(){const width=span.scrollWidth;const height=span.scrollHeight;setLabelMargins(span,[width,height]);});};$span.processText=function(text){$span.html(text);const width=span.scrollWidth;const height=span.scrollHeight;setLabelMargins(span,[width,height]);};if(latex){$span.processMath(text,false);}else {$span.processText(text);}this._ensureResizeObserver();return $span})};this.svgPath=(points,alreadyScaled)=>{return points.map((point,i)=>{if(point===true){return "z"}const scaled=alreadyScaled?point:this.scalePoint(point);return (i===0?"M":"L")+kmath.KhanMath.bound(scaled[0])+" "+kmath.KhanMath.bound(scaled[1])}).join("")};this.svgParabolaPath=(a,b,c)=>{const computeParabola=function(x){return (a*x+b)*x+c};if(a===0){const points=[[this.bounds().xMin,computeParabola(this.bounds().xMin)],[this.bounds().xMax,computeParabola(this.bounds().xMax)]];return this.svgPath(points)}const xVertex=-b/(2*a);const distToEdge=Math.max(Math.abs(xVertex-this.bounds().xMin),Math.abs(xVertex-this.bounds().xMax));const xPoint=xVertex+distToEdge;const vertex=[xVertex,computeParabola(xVertex)];const point=[xPoint,computeParabola(xPoint)];const control=[vertex[0],vertex[1]-(point[1]-vertex[1])];const dx=Math.abs(vertex[0]-point[0]);const left=[vertex[0]-dx,point[1]];const right=[vertex[0]+dx,point[1]];const points=[left,control,right].map(this.scalePoint);const values=points.flat().map(kmath.KhanMath.bound);return "M"+values[0]+","+values[1]+" Q"+values[2]+","+values[3]+" "+values[4]+","+values[5]};this.svgSinusoidPath=(a,b,c,d)=>{const quarterPeriod=Math.abs(Math.PI/(2*b));const computeSine=function(x){return a*Math.sin(b*x-c)+d};const computeDerivative=function(x){return a*b*Math.cos(c-b*x)};const coordsForOffset=(initial,i)=>{const x0=initial+quarterPeriod*i;const x1=x0+quarterPeriod;const xCoords=[x0,x0*2/3+x1*1/3,x0*1/3+x1*2/3,x1];const yCoords=[computeSine(x0),computeSine(x0)+computeDerivative(x0)*(x1-x0)/3,computeSine(x1)-computeDerivative(x1)*(x1-x0)/3,computeSine(x1)];const points=kmath.vector.zip(xCoords,yCoords);return points.map(this.scalePoint)};const extent=this.bounds().width();const numQuarterPeriods=Math.ceil(extent/quarterPeriod)+1;let initial=c/b;const distToEdge=initial-this.bounds().xMin;initial-=quarterPeriod*Math.ceil(distToEdge/quarterPeriod);let coords=coordsForOffset(initial,0);let path="M"+coords[0][0]+","+coords[0][1]+" C"+coords[1][0]+","+coords[1][1]+" "+coords[2][0]+","+coords[2][1]+" "+coords[3][0]+","+coords[3][1];for(let i=1;i<numQuarterPeriods;i++){coords=coordsForOffset(initial,i);path+=" C"+coords[1][0]+","+coords[1][1]+" "+coords[2][0]+","+coords[2][1]+" "+coords[3][0]+","+coords[3][1];}return path};this.scalePoint=point=>{return this.drawingTransform().scalePoint(point)};this.scaleVector=point=>{return this.drawingTransform().scaleVector(point)};this.unscalePoint=point=>{return this.drawingTransform().unscalePoint(point)};this.unscaleVector=point=>{return this.drawingTransform().unscaleVector(point)};this.el=el;$__default.default(el).css("position","relative");this.raphael=Raphael$1(el);$__default.default(el).attr("aria-hidden","true");$__default.default(el).children("div").css("position","absolute");}};const labelDirections={center:[-0.5,-0.5],above:[-0.5,-1],"above right":[0,-1],right:[0,-0.5],"below right":[0,0],below:[-0.5,0],"below left":[-1,0],left:[-1,-0.5],"above left":[-1,-1]};function normalizeRange(range){function normalizeInterval(magnitude){if(typeof magnitude==="number"){return [-magnitude,magnitude]}else {return magnitude}}function getXAndYRanges(range){if(Array.isArray(range)){return range}else {return [range,range]}}if(range==null){return range}const[xRange,yRange]=getXAndYRanges(range);return [normalizeInterval(xRange),normalizeInterval(yRange)]}function toPair(x){if(Array.isArray(x)){return x}return [x,x]}const SVG_SPECIFIC_STYLE_MASK={"stroke-width":null};const setLabelMargins=function(span,size){if(document.fonts?.status==="loading"){document.fonts.ready.then(()=>applyLabelMargins(span,size));return}applyLabelMargins(span,size);};const applyLabelMargins=function(span,size){const $span=$__default.default(span);const direction=$span.data("labelDirection");let[width,height]=size;if(width===0&&height===0){[width,height]=[1,1];Log.log("Label size was 0x0 in graphie.js; using 1x1 instead");}$span.css("visibility","");if(typeof direction==="number"){const x=Math.cos(direction);const y=Math.sin(direction);const scale=Math.min(width/2/Math.abs(x),height/2/Math.abs(y));$span.css({marginLeft:-width/2+x*scale,marginTop:-height/2-y*scale});if($span.data("originalLabelSize")==null){$span.data("originalLabelSize",[width,height]);}}else {const $svgImage=$span.closest(".svg-image");const $graphie=$span.closest(".graphie");const $container=$svgImage.length>0?$svgImage:$graphie;$container.css("line-height","normal");if($span.data("originalLabelSize")==null){height=span.scrollHeight;$span.data("originalLabelSize",[width,height]);}const widthValues=$container.css(["max-width","width"])??{"max-width":"0px"};const expectedWidth=widthValues["max-width"]!=="none"?widthValues["max-width"]:widthValues["width"];let scale=($container.width()??0)/parseInt(expectedWidth.replace(/px$/,""));if(isNaN(scale)){scale=1;}else if(scale===0){scale=1;}let rawPadding;const storedPadding=$span.data("originalPadding");if(storedPadding!=null){rawPadding=storedPadding;}else {const padding=$span.css("padding")??"0px";const currentPadding=padding!=="none"?padding:"0px";rawPadding=parseInt(currentPadding.replace(/px$/,""));$span.data("originalPadding",rawPadding);}let normalizedWidth=width;let normalizedHeight=height;const imageScale=Number($container.attr("data-scale"));const hasValidImageScale=!Number.isNaN(imageScale)&&imageScale>=0;if(hasValidImageScale){scale=scale*imageScale;const totalPadding=2*rawPadding;normalizedWidth=(width-totalPadding)/imageScale+totalPadding;normalizedHeight=(height-totalPadding)/imageScale+totalPadding;}const newPadding=rawPadding*scale;const multipliers=labelDirections[direction||"center"];const styling={marginLeft:normalizedWidth*multipliers[0]*scale,marginTop:normalizedHeight*multipliers[1]*scale,padding:`${newPadding}px`,fontSize:`${scale*100}%`};$span.css(styling);}};const GraphUtils={Graphie: Graphie$1,createGraphie:function(el){return new Graphie$1(el)},unscaledSvgPath:function(points){if(points[0]===true){return ""}return points.map(function(point,i){if(point===true){return "z"}return (i===0?"M":"L")+point[0]+" "+point[1]}).join("")},getDistance:function(point1,point2){return kmath.point.distanceToPoint(point1,point2)},findAngleDeprecated:function(point1,point2,vertex){if(vertex===undefined){const x=point1[0]-point2[0];const y=point1[1]-point2[1];if(!x&&!y){return 0}return (180+Math.atan2(-y,-x)*180/Math.PI+360)%360}return GraphUtils.findAngleDeprecated(point1,vertex)-GraphUtils.findAngleDeprecated(point2,vertex)},graphs:{}};
1619
1619
 
1620
1620
  (function($,window1,document1,undefined$1){if(typeof $==="undefined"){return}var dataPropertyName="virtualMouseBindings",touchTargetPropertyName="virtualTouchID",virtualEventNames="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),touchEventProps="clientX clientY pageX pageY screenX screenY".split(" "),mouseHookProps=$.event.mouseHooks?$.event.mouseHooks.props:[],mouseEventProps=$.event.props.concat(mouseHookProps),activeDocHandlers={},resetTimerID=0,startX=0,startY=0,didScroll=false,clickBlockList=[],blockMouseTriggers=false,blockTouchTriggers=false,eventCaptureSupported="addEventListener"in document1,$document=$(document1),nextTouchID=1,lastTouchID=0;$.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};function getNativeEvent(event){while(event&&typeof event.originalEvent!=="undefined"){event=event.originalEvent;}return event}function createVirtualEvent(event,eventType){var t=event.type,oe,props,ne,prop,ct,touch,i,j,len;event=$.Event(event);event.type=eventType;oe=event.originalEvent;props=$.event.props;if(t.search(/mouse/)>-1){props=mouseEventProps;}if(oe){for(i=props.length,prop;i;){prop=props[--i];event[prop]=oe[prop];}}if(t.search(/mouse(down|up)|click/)>-1&&!event.which){event.which=1;}if(t.search(/^touch/)!==-1){ne=getNativeEvent(oe);t=ne.touches;ct=ne.changedTouches;touch=t&&t.length?t[0]:ct&&ct.length?ct[0]:undefined$1;if(touch){for(j=0,len=touchEventProps.length;j<len;j++){prop=touchEventProps[j];event[prop]=touch[prop];}}}return event}function getVirtualBindingFlags(element){var flags={},b,k;while(element){b=$.data(element,dataPropertyName);for(k in b){if(b[k]){flags[k]=flags.hasVirtualBinding=true;}}element=element.parentNode;}return flags}function getClosestElementWithVirtualBinding(element,eventType){var b;while(element){b=$.data(element,dataPropertyName);if(b&&(!eventType||b[eventType])){return element}element=element.parentNode;}return null}function enableTouchBindings(){blockTouchTriggers=false;}function disableTouchBindings(){blockTouchTriggers=true;}function enableMouseBindings(){lastTouchID=0;clickBlockList.length=0;blockMouseTriggers=false;disableTouchBindings();}function disableMouseBindings(){enableTouchBindings();}function startResetTimer(){clearResetTimer();resetTimerID=setTimeout(function(){resetTimerID=0;enableMouseBindings();},$.vmouse.resetTimerDuration);}function clearResetTimer(){if(resetTimerID){clearTimeout(resetTimerID);resetTimerID=0;}}function triggerVirtualEvent(eventType,event,flags){var ve;if(flags&&flags[eventType]||!flags&&getClosestElementWithVirtualBinding(event.target,eventType)){ve=createVirtualEvent(event,eventType);$(event.target).trigger(ve);}return ve}function mouseEventCallback(event){var touchID=$.data(event.target,touchTargetPropertyName);if(!blockMouseTriggers&&(!lastTouchID||lastTouchID!==touchID)){var ve=triggerVirtualEvent("v"+event.type,event);if(ve){if(ve.isDefaultPrevented()){event.preventDefault();}if(ve.isPropagationStopped()){event.stopPropagation();}if(ve.isImmediatePropagationStopped()){event.stopImmediatePropagation();}}}}function handleTouchStart(event){var touches=getNativeEvent(event).touches,target,flags;if(touches&&touches.length===1){target=event.target;flags=getVirtualBindingFlags(target);if(flags.hasVirtualBinding){lastTouchID=nextTouchID++;$.data(target,touchTargetPropertyName,lastTouchID);clearResetTimer();disableMouseBindings();didScroll=false;var t=getNativeEvent(event).touches[0];startX=t.pageX;startY=t.pageY;triggerVirtualEvent("vmouseover",event,flags);triggerVirtualEvent("vmousedown",event,flags);}}}function handleScroll(event){if(blockTouchTriggers){return}if(!didScroll){triggerVirtualEvent("vmousecancel",event,getVirtualBindingFlags(event.target));}didScroll=true;startResetTimer();}function handleTouchMove(event){if(blockTouchTriggers){return}var t=getNativeEvent(event).touches[0],didCancel=didScroll,moveThreshold=$.vmouse.moveDistanceThreshold,didScroll=didScroll||Math.abs(t.pageX-startX)>moveThreshold||Math.abs(t.pageY-startY)>moveThreshold,flags=getVirtualBindingFlags(event.target);if(didScroll&&!didCancel){triggerVirtualEvent("vmousecancel",event,flags);}triggerVirtualEvent("vmousemove",event,flags);startResetTimer();}function handleTouchEnd(event){if(blockTouchTriggers){return}disableTouchBindings();var flags=getVirtualBindingFlags(event.target),t;triggerVirtualEvent("vmouseup",event,flags);if(!didScroll){var ve=triggerVirtualEvent("vclick",event,flags);if(ve&&ve.isDefaultPrevented()){t=getNativeEvent(event).changedTouches[0];clickBlockList.push({touchID:lastTouchID,x:t.clientX,y:t.clientY});blockMouseTriggers=true;}}triggerVirtualEvent("vmouseout",event,flags);didScroll=false;startResetTimer();}function hasVirtualBindings(ele){var bindings=$.data(ele,dataPropertyName),k;if(bindings){for(k in bindings){if(bindings[k]){return true}}}return false}function dummyMouseHandler(){}function getSpecialEventObject(eventType){var realType=eventType.substr(1);return {setup:function(data,namespace){if(!hasVirtualBindings(this)){$.data(this,dataPropertyName,{});}var bindings=$.data(this,dataPropertyName);bindings[eventType]=true;activeDocHandlers[eventType]=(activeDocHandlers[eventType]||0)+1;if(activeDocHandlers[eventType]===1){$document.bind(realType,mouseEventCallback);}$(this).bind(realType,dummyMouseHandler);if(eventCaptureSupported){activeDocHandlers["touchstart"]=(activeDocHandlers["touchstart"]||0)+1;if(activeDocHandlers["touchstart"]===1){$document.bind("touchstart",handleTouchStart).bind("touchend",handleTouchEnd).bind("touchmove",handleTouchMove).bind("scroll",handleScroll);}}},teardown:function(data,namespace){--activeDocHandlers[eventType];if(!activeDocHandlers[eventType]){$document.unbind(realType,mouseEventCallback);}if(eventCaptureSupported){--activeDocHandlers["touchstart"];if(!activeDocHandlers["touchstart"]){$document.unbind("touchstart",handleTouchStart).unbind("touchmove",handleTouchMove).unbind("touchend",handleTouchEnd).unbind("scroll",handleScroll);}}var $this=$(this),bindings=$.data(this,dataPropertyName);if(bindings){bindings[eventType]=false;}$this.unbind(realType,dummyMouseHandler);if(!hasVirtualBindings(this)){$this.removeData(dataPropertyName);}}}}for(var i=0;i<virtualEventNames.length;i++){$.event.special[virtualEventNames[i]]=getSpecialEventObject(virtualEventNames[i]);}if(eventCaptureSupported){document1.addEventListener("click",function(e){var cnt=clickBlockList.length,target=e.target,x,y,ele,i,o;if(cnt){x=e.clientX;y=e.clientY;threshold=$.vmouse.clickDistanceThreshold;ele=target;while(ele){for(i=0;i<cnt;i++){o=clickBlockList[i];if(ele===target&&Math.abs(o.x-x)<threshold&&Math.abs(o.y-y)<threshold||$.data(ele,touchTargetPropertyName)===o.touchID){e.preventDefault();e.stopPropagation();return}}ele=ele.parentNode;}}},true);}})($__default.default,window,document);
1621
1621
 
@@ -1657,19 +1657,19 @@ const Interactive2={MovablePoint:MovablePoint$5,addMovablePoint:function(graphie
1657
1657
 
1658
1658
  const MovablePoint$4=GraphieClasses.createClass({displayName:"MovablePoint",movableProps:["children"],_getProps:function(){if(this.props.isMobile){const isMobile=this.props.isMobile;const commonStyle=isMobile?{stroke:"#ffffff","stroke-width":3,fill:KhanColors.INTERACTIVE}:{stroke:KhanColors.INTERACTIVE,fill:KhanColors.INTERACTIVE};const normalStyle=isMobile?Object.assign(commonStyle,this.props.mobileStyleOverride||{}):Object.assign(commonStyle,this.props.normalStyle);const highlightStyle=isMobile?{...commonStyle,"stroke-width":0,scale:.75}:this.props.highlightStyle;const addedProps=Object.assign({normalStyle:normalStyle,highlightStyle:highlightStyle,shadow:isMobile,tooltip:isMobile&&this.props.showTooltips},isMobile?{pointSize:7}:{});return Object.assign(this.props,addedProps)}return this.props},add:function(graphie){this.point=Interactive2.addMovablePoint(graphie,this._getProps());},modify:function(){this.point.modify(this._getProps());},remove:function(){this.point.remove();},toFront:function(){this.point.toFront();},grab:function(coord){this.point.grab(coord);}});___default.default.extend(MovablePoint$4,Interactive2.MovablePoint);const MovableLine$3=GraphieClasses.createClass({displayName:"MovableLine",movableProps:["children"],add:function(graphie){const points=___default.default.pluck(this.props.children,"point");const props=___default.default.extend({},this.props,{points:points});this.line=Interactive2.addMovableLine(graphie,props);},modify:function(){const points=___default.default.pluck(this.props.children,"point");const props=___default.default.extend({},this.props,{points:points});this.line.modify(props);},remove:function(){this.line.remove();},toFront:function(){this.line.toFront();}});___default.default.extend(MovableLine$3,Interactive2.MovableLine);const Label$1=GraphieClasses.createSimpleClass((graphie,props)=>{let coord=props.coord;if(props.unscaled){coord=graphie.unscalePoint(coord);}let elem;if(getDependencies().JIPT.useJIPT){elem=graphie.label(coord,props.text,props.direction,false,props.style);getDependencies().graphieMovablesJiptLabels.addLabel(elem,props.tex);}else {elem=graphie.label(coord,props.text,props.direction,props.tex,props.style);}return elem});const Line$3=GraphieClasses.createClass({displayName:"Line",movableProps:["children"],add:function(graphie){const props=this.props;this.graphie=graphie;this.line=this.graphie.line(props.start,props.end,props.style);},modify:function(){const props=this.props;const path=this.graphie.svgPath([props.start,props.end]);this.line.attr(___default.default.extend({},props.style,{path:path}));},remove:function(){this.line.remove();},toFront:function(){this.line.toFront();}});const Parabola=GraphieClasses.createClass({displayName:"Parabola",movableProps:["children"],add:function(graphie){const props=this.props;this.graphie=graphie;this.parabola=this.graphie.parabola(props.a,props.b,props.c,props.style);},modify:function(){const props=this.props;const path=this.graphie.svgParabolaPath(props.a,props.b,props.c);this.parabola.attr(___default.default.extend({},props.style,{path:path}));},remove:function(){this.parabola.remove();},toFront:function(){this.parabola.toFront();}});const Sinusoid=GraphieClasses.createClass({displayName:"Sinusoid",movableProps:["children"],add:function(graphie){const props=this.props;this.graphie=graphie;this.sinusoid=this.graphie.sinusoid(props.a,props.b,props.c,props.d,props.style);},modify:function(){const props=this.props;const path=this.graphie.svgSinusoidPath(props.a,props.b,props.c,props.d);this.sinusoid.attr(___default.default.extend({},props.style,{path:path}));},remove:function(){this.sinusoid.remove();},toFront:function(){this.sinusoid.toFront();}});const Plot$1=GraphieClasses.createSimpleClass((graphie,props)=>{return graphie.plot(props.fn,props.range,props.style)});const PlotParametric$1=GraphieClasses.createSimpleClass((graphie,props)=>{return graphie.plotParametric(props.fn,props.range,props.style)});const Point$1=GraphieClasses.createSimpleClass((graphie,props)=>{return graphie.ellipse(props.coord,graphie.unscaleVector([4,4]),{fill:props.color||KhanColors.BLACK,stroke:props.color||KhanColors.BLACK})});const Path=GraphieClasses.createClass({displayName:"Path",movableProps:["children"],add:function(graphie){const props=this.props;this.graphie=graphie;this.path=this.graphie.path(props.coords,props.style);},modify:function(){const props=this.props;const path=this.graphie.svgPath(props.coords);this.path.attr({path:path});},remove:function(){this.path.remove();},toFront:function(){this.path.toFront();}});const Arc$1=GraphieClasses.createSimpleClass((graphie,props)=>{let center=props.center;let radius=props.radius;if(props.unscaled){center=graphie.unscalePoint(center);radius=graphie.unscaleVector(radius);}return graphie.arc(center,radius,props.startAngle,props.endAngle,props.sector,props.style)});const Circle=GraphieClasses.createSimpleClass((graphie,props)=>{return graphie.circle(props.center,props.radius,props.style)});const Rect$1=GraphieClasses.createSimpleClass((graphie,props)=>{return graphie.rect(props.x,props.y,props.width,props.height,props.style)});var Movables = {Arc:Arc$1,Circle:Circle,Label:Label$1,Line:Line$3,MovableLine:MovableLine$3,MovablePoint:MovablePoint$4,Parabola:Parabola,Path:Path,Plot:Plot$1,PlotParametric:PlotParametric$1,Point:Point$1,Sinusoid:Sinusoid,Rect:Rect$1};
1659
1659
 
1660
- 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();}componentWillUnmount(){this._graphie.cleanup();}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._graphie.cleanup();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);
1660
+ 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();}componentWillUnmount(){this._graphie.cleanup();}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._graphie.cleanup();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});}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);
1661
1661
 
1662
1662
  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;const{alt,title,...restImgProps}=imgProps;return jsxRuntimeExports.jsx("img",{alt:alt,title:title,className:"image-loader-img",src:this.props.dependencies.generateUrl({url:src,context:"image_loader:image_url"}),style:{display:"block",...imgProps.style??{width:"100%"}},...restImgProps})};this.state={status:props.src?Status.LOADING:Status.PENDING};}}var ImageLoader$1 = withDependencies(ImageLoader);
1663
1663
 
1664
1664
  function isGif(url){return url.endsWith(".gif")}function isSvg(url){const hasSvgExtension=url.endsWith(".svg");const hasGraphieUrl=perseusCore.isLabeledSVG(url);return hasSvgExtension||hasGraphieUrl}
1665
1665
 
1666
- var styles$B = {"contentWrapper":"perseus_NqTCZY3N","imageContainer":"perseus_Ctn3miye"};
1666
+ var styles$C = {"contentWrapper":"perseus_NqTCZY3N","imageContainer":"perseus_Ctn3miye"};
1667
1667
 
1668
- const WB_MODAL_PADDING_TOTAL=64;const ZoomedImageView=props=>{const i18n=usePerseusI18n();const{initialFocusId,onClose,...svgProps}=props;const width=props.width;const height=props.height;const contentScale=props.scale;const imageIsSvg=isSvg(props.src);const scale=imageIsSvg?Math.max(contentScale,2):Math.max(contentScale,1);const maxAvailableWidth=window.innerWidth-WB_MODAL_PADDING_TOTAL;const maxAvailableHeight=window.innerHeight-WB_MODAL_PADDING_TOTAL;const scaleWidth=maxAvailableWidth/(width*scale);const scaleHeight=maxAvailableHeight/(height*scale);const fitRatio=Math.min(scaleWidth,scaleHeight,1);const constrainedDisplayWidth=width*fitRatio*scale;return jsxRuntimeExports.jsx(wonderBlocksModal.ModalDialog,{"aria-labelledby":"",style:wbStyles$2.dialog,children:jsxRuntimeExports.jsx(wonderBlocksModal.ModalPanel,{closeButtonVisible:false,content:jsxRuntimeExports.jsxs("div",{className:styles$B.contentWrapper,children:[jsxRuntimeExports.jsx("div",{className:styles$B.imageContainer,style:{width:constrainedDisplayWidth},children:jsxRuntimeExports.jsx("div",{className:"framework-perseus",tabIndex:0,id:initialFocusId,children:jsxRuntimeExports.jsx(SvgImage,{...svgProps,allowZoom:false,width:width,height:height,scale:scale})})}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:closeIcon__default.default,onClick:onClose,"aria-label":i18n.strings.imageResetZoomAriaLabel,kind:"primary",style:wbStyles$2.closeButton})]})})})};const wbStyles$2=aphrodite.StyleSheet.create({dialog:{width:"auto",height:"auto",margin:wonderBlocksTokens.sizing.size_320,"@media (max-width: 767px)":{margin:0}},closeButton:{position:"absolute",top:wonderBlocksTokens.border.width.medium,right:wonderBlocksTokens.border.width.medium,opacity:0,":hover":{opacity:1},":focus":{opacity:1}}});
1668
+ const WB_MODAL_PADDING_TOTAL=64;const ZoomedImageView=props=>{const i18n=usePerseusI18n();const{initialFocusId,onClose,...svgProps}=props;const width=props.width;const height=props.height;const contentScale=props.scale;const imageIsSvg=isSvg(props.src);const scale=imageIsSvg?Math.max(contentScale,2):Math.max(contentScale,1);const maxAvailableWidth=window.innerWidth-WB_MODAL_PADDING_TOTAL;const maxAvailableHeight=window.innerHeight-WB_MODAL_PADDING_TOTAL;const scaleWidth=maxAvailableWidth/(width*scale);const scaleHeight=maxAvailableHeight/(height*scale);const fitRatio=Math.min(scaleWidth,scaleHeight,1);const constrainedDisplayWidth=width*fitRatio*scale;return jsxRuntimeExports.jsx(wonderBlocksModal.ModalDialog,{"aria-labelledby":"",style:wbStyles$2.dialog,children:jsxRuntimeExports.jsx(wonderBlocksModal.ModalPanel,{closeButtonVisible:false,content:jsxRuntimeExports.jsxs("div",{className:styles$C.contentWrapper,children:[jsxRuntimeExports.jsx("div",{className:styles$C.imageContainer,style:{width:constrainedDisplayWidth},children:jsxRuntimeExports.jsx("div",{className:"framework-perseus",tabIndex:0,id:initialFocusId,children:jsxRuntimeExports.jsx(SvgImage,{...svgProps,allowZoom:false,width:width,height:height,scale:scale})})}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:closeIcon__default.default,onClick:onClose,"aria-label":i18n.strings.imageResetZoomAriaLabel,kind:"primary",style:wbStyles$2.closeButton})]})})})};const wbStyles$2=aphrodite.StyleSheet.create({dialog:{width:"auto",height:"auto",margin:wonderBlocksTokens.sizing.size_320,"@media (max-width: 767px)":{margin:0}},closeButton:{position:"absolute",top:wonderBlocksTokens.border.width.medium,right:wonderBlocksTokens.border.width.medium,opacity:0,":hover":{opacity:1},":focus":{opacity:1}}});
1669
1669
 
1670
1670
  const ZoomImageButton=props=>{const{imgSrc}=props;const i18n=usePerseusI18n();const uniqueId=React__namespace.useId().replace(/:/g,"");const zoomedImageUniqueId=`zoomed-image-${uniqueId}`;const handleClick=(event,openModal)=>{const mouseEvent=event;if(mouseEvent.metaKey||mouseEvent.ctrlKey){window.open(imgSrc,"_blank");}else {openModal();}};return jsxRuntimeExports.jsx(wonderBlocksModal.ModalLauncher,{initialFocusId:zoomedImageUniqueId,modal:({closeModal})=>jsxRuntimeExports.jsx(ZoomedImageView,{...props,initialFocusId:zoomedImageUniqueId,onClose:closeModal}),children:({openModal})=>jsxRuntimeExports.jsx(Clickable__default.default,{"aria-label":i18n.strings.imageZoomAriaLabel,onClick:event=>handleClick(event,openModal),style:{position:"absolute",width:"100%",height:"100%",overflow:"hidden",cursor:"zoom-in"},children:()=>{return jsxRuntimeExports.jsx(React__namespace.Fragment,{})}})})};
1671
1671
 
1672
- 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._isLoadingGraphie=false;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._isLoadingGraphie){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(){this._isLoadingGraphie=true;loadGraphie(this.props.src,(data,localized)=>{this._isLoadingGraphie=false;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 isGifControlled=this.props.isGifPlaying!==undefined;const imageContent=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[!isGifControlled&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageSrc,imgProps:imageProps,preloader:preloader,onUpdate:this.handleUpdate}),extraGraphie]}),isGifControlled&&jsxRuntimeExports.jsx(GifImage,{src:imageSrc,alt:this.props.alt,width:this.props.width,height:this.props.height,scale:this.props.scale,isPlaying:!!this.props.isGifPlaying,onLoop:this.props.onGifLoop??(()=>{}),onLoad:this.onImageLoad})]});return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,allowFullBleed:this.props.allowFullBleed&&isImageProbablyPhotograph(imageSrc),scale:this.props.scale,children:[imageContent,this.props.allowZoom&&jsxRuntimeExports.jsx(ZoomImageButton,{...this.props,imgSrc:imageSrc,width:this.props.width,height:this.props.height})]})}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){const imageContent=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:preloader,imgProps:imageProps}),graphie,extraGraphie]});return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,scale:this.props.scale,children:[imageContent,this.props.allowZoom&&jsxRuntimeExports.jsx(ZoomImageButton,{...this.props,imgSrc:imageUrl,width:this.props.width,height:this.props.height})]})}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)=>{const newLabelsRendered={};___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);});}newLabelsRendered[labelData.content]=true;});this.setState(prev=>({labelsRendered:{...prev.labelsRendered,...newLabelsRendered}}));},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._isLoadingGraphie=false;this.state={imageLoaded:false,imageDimensions:null,dataLoaded:false,labelDataIsLocalized:false,labels:[],labelsRendered:{},range:[[0,0],[0,0]]};}}SvgImage.contextType=PerseusI18nContext;SvgImage.defaultProps={constrainHeight:false,onUpdate:()=>{},responsive:true,src:"",scale:1,zoomToFullSizeOnMobile:false,setAssetStatus:(src,status)=>{}};
1672
+ function isImageProbablyPhotograph(imageUrl){return /\.(jpg|jpeg)$/i.test(imageUrl)}function spinner(){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._isLoadingGraphie=false;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._isLoadingGraphie){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(){this._isLoadingGraphie=true;loadGraphie(this.props.src,(data,localized)=>{this._isLoadingGraphie=false;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});}if(!Util.isLabeledSVG(imageSrc)){if(responsive){const isGifControlled=this.props.isGifPlaying!==undefined;const imageContent=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[!isGifControlled&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageSrc,imgProps:imageProps,preloader:spinner,onUpdate:this.handleUpdate}),extraGraphie]}),isGifControlled&&jsxRuntimeExports.jsx(GifImage,{src:imageSrc,alt:this.props.alt,width:this.props.width,height:this.props.height,scale:this.props.scale,isPlaying:!!this.props.isGifPlaying,onLoop:this.props.onGifLoop??(()=>{}),onLoad:this.onImageLoad})]});return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,allowFullBleed:this.props.allowFullBleed&&isImageProbablyPhotograph(imageSrc),scale:this.props.scale,children:[imageContent,this.props.allowZoom&&jsxRuntimeExports.jsx(ZoomImageButton,{...this.props,imgSrc:imageSrc,width:this.props.width,height:this.props.height})]})}imageProps.style=dimensions;return jsxRuntimeExports.jsx(ImageLoader$1,{src:imageSrc,preloader:spinner,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){const imageContent=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageLoader$1,{src:imageUrl,onLoad:this.onImageLoad,onUpdate:this.handleUpdate,preloader:spinner,imgProps:imageProps}),graphie,extraGraphie]});return jsxRuntimeExports.jsxs(FixedToResponsive,{className:"svg-image",width:width,height:height,constrainHeight:this.props.constrainHeight,scale:this.props.scale,children:[imageContent,this.props.allowZoom&&jsxRuntimeExports.jsx(ZoomImageButton,{...this.props,imgSrc:imageUrl,width:this.props.width,height:this.props.height})]})}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:spinner,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)=>{const newLabelsRendered={};___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);});}newLabelsRendered[labelData.content]=true;});this.setState(prev=>({labelsRendered:{...prev.labelsRendered,...newLabelsRendered}}));},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._isLoadingGraphie=false;this.state={imageLoaded:false,imageDimensions:null,dataLoaded:false,labelDataIsLocalized:false,labels:[],labelsRendered:{},range:[[0,0],[0,0]]};}}SvgImage.contextType=PerseusI18nContext;SvgImage.defaultProps={constrainHeight:false,onUpdate:()=>{},responsive:true,src:"",scale:1,zoomToFullSizeOnMobile:false,setAssetStatus:(src,status)=>{}};
1673
1673
 
1674
1674
  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)=>{}};
1675
1675
 
@@ -1687,7 +1687,7 @@ const arrayRules={fence:{match:SimpleMarkdown__default.default.defaultRules.fenc
1687
1687
 
1688
1688
  const denylist=["key","ref","containerSizeClass","widgetId","onChange","problemNum","apiOptions","widgetIsOpen","findWidgets","onRemove","id","onBlur","onFocus","trackInteraction","keypadElement","linterContext","handleUserInput","analytics","showSolutions","reviewMode","widgetIndex","graded"];function excludeDenylistKeys(obj){if(obj==null){return obj}const rv={};for(const k of Object.keys(obj)){if(!denylist.includes(k)){rv[k]=obj[k];}}return rv}
1689
1689
 
1690
- const exclamationIcon={path:"M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",height:12,width:12};class Lint extends React__namespace.Component{componentDidMount(){this._positionTimeout=window.setTimeout(this.getPosition);}componentWillUnmount(){window.clearTimeout(this._positionTimeout);}render(){const{children,inline,blockHighlight,insideTable}=this.props;if(insideTable){if(inline){return jsxRuntimeExports.jsx("span",{"data-lint-inside-table":"true",children:children})}return jsxRuntimeExports.jsx("div",{"data-lint-inside-table":"true",children:children})}if(blockHighlight){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$A.lintContainer,styles$A.lintContainerBlock),children:[this.renderLink(styles$A.radioWidgetHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}if(inline){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$A.lintContainer),children:[this.renderLink(styles$A.inlineHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$A.lintContainer),children:[this.renderLink(styles$A.hoverTarget),jsxRuntimeExports.jsx("div",{children:children})]})}constructor(...args){super(...args),this.state={tooltipAbove:true},this.getPosition=()=>{const rect=ReactDOM__namespace.default.findDOMNode(this).getBoundingClientRect();this.setState({tooltipAbove:rect.top>100});},this.renderLink=style=>{const tooltipAbove=this.state.tooltipAbove;let severityStyle;let warningText;let warningTextStyle;if(this.props.severity===1){severityStyle=styles$A.indicatorError;warningText="Error";warningTextStyle=styles$A.publishBlockingError;}else if(this.props.severity===2){severityStyle=styles$A.indicatorWarning;warningText="Warning";warningTextStyle=styles$A.warning;}else {severityStyle=styles$A.indicatorGuideline;warningText="Recommendation";warningTextStyle=styles$A.warning;}return jsxRuntimeExports.jsxs("a",{href:`https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,target:"lint-help-window",className:aphrodite.css(style),children:[jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$A.indicator,severityStyle),children:this.props.severity===1&&jsxRuntimeExports.jsx(InlineIcon,{...exclamationIcon})}),jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$A.tooltip,tooltipAbove&&styles$A.tooltipAbove),children:[this.props.message.split("\n\n").map((m,i)=>jsxRuntimeExports.jsxs("p",{className:aphrodite.css(styles$A.tooltipParagraph),children:[jsxRuntimeExports.jsxs("span",{className:aphrodite.css(warningTextStyle),children:[warningText,":"," "]}),m]},i)),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$A.tail,tooltipAbove&&styles$A.tailAbove)})]})]})};}}const styles$A=aphrodite.StyleSheet.create({lintContainer:{position:"relative"},lintContainerBlock:{display:"block"},hoverTarget:{position:"absolute",top:0,right:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ div":{outline:"1px solid "+warningColor},":hover ~ div div[data-lint-inside-table]":{outline:"1px solid "+warningColor},":hover ~ div span[data-lint-inside-table]":{backgroundColor:warningColor,color:white}},inlineHoverTarget:{float:"right",position:"relative",marginRight:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ span":{backgroundColor:warningColor,color:white}},radioWidgetHoverTarget:{position:"absolute",left:-40,display:"block",width:24,height:24,minWidth:264,":hover > span":{backgroundColor:warningColorHover},":hover > div":{display:"block",padding:8,width:280},":hover > div > div":{left:8},":hover ~ span":{backgroundColor:warningColor,color:white}},indicator:{alignItems:"center",borderRadius:4,color:"white",display:"flex",fontSize:12,height:8,justifyContent:"center",margin:8,width:8},indicatorError:{backgroundColor:"#be2612",borderRadius:8,height:16,width:16},indicatorWarning:{backgroundColor:"#f86700"},indicatorGuideline:{backgroundColor:"#ffbe26"},tooltip:{position:"absolute",right:-12,display:"none",zIndex:1e3,color:white,backgroundColor:gray17,opacity:.9,fontFamily:baseFontFamily,fontSize:"12px",lineHeight:"15px",width:"320px",borderRadius:"4px"},tooltipAbove:{bottom:32},tail:{position:"absolute",top:-12,right:16,width:0,height:0,borderLeft:"8px solid transparent",borderRight:"8px solid transparent",borderBottom:"12px solid "+gray17},tailAbove:{bottom:-12,borderBottom:"none",borderTop:"12px solid "+gray17,top:"auto"},tooltipParagraph:{margin:12},warning:{color:warningColor,fontFamily:boldFontFamily},publishBlockingError:{color:publishBlockingErrorColor}});
1690
+ const exclamationIcon={path:"M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",height:12,width:12};class Lint extends React__namespace.Component{componentDidMount(){this._positionTimeout=window.setTimeout(this.getPosition);}componentWillUnmount(){window.clearTimeout(this._positionTimeout);}render(){const{children,inline,blockHighlight,insideTable}=this.props;if(insideTable){if(inline){return jsxRuntimeExports.jsx("span",{"data-lint-inside-table":"true",children:children})}return jsxRuntimeExports.jsx("div",{"data-lint-inside-table":"true",children:children})}if(blockHighlight){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$B.lintContainer,styles$B.lintContainerBlock),children:[this.renderLink(styles$B.radioWidgetHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}if(inline){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$B.lintContainer),children:[this.renderLink(styles$B.inlineHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$B.lintContainer),children:[this.renderLink(styles$B.hoverTarget),jsxRuntimeExports.jsx("div",{children:children})]})}constructor(...args){super(...args),this.state={tooltipAbove:true},this.getPosition=()=>{const rect=ReactDOM__namespace.default.findDOMNode(this).getBoundingClientRect();this.setState({tooltipAbove:rect.top>100});},this.renderLink=style=>{const tooltipAbove=this.state.tooltipAbove;let severityStyle;let warningText;let warningTextStyle;if(this.props.severity===1){severityStyle=styles$B.indicatorError;warningText="Error";warningTextStyle=styles$B.publishBlockingError;}else if(this.props.severity===2){severityStyle=styles$B.indicatorWarning;warningText="Warning";warningTextStyle=styles$B.warning;}else {severityStyle=styles$B.indicatorGuideline;warningText="Recommendation";warningTextStyle=styles$B.warning;}return jsxRuntimeExports.jsxs("a",{href:`https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,target:"lint-help-window",className:aphrodite.css(style),children:[jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$B.indicator,severityStyle),children:this.props.severity===1&&jsxRuntimeExports.jsx(InlineIcon,{...exclamationIcon})}),jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$B.tooltip,tooltipAbove&&styles$B.tooltipAbove),children:[this.props.message.split("\n\n").map((m,i)=>jsxRuntimeExports.jsxs("p",{className:aphrodite.css(styles$B.tooltipParagraph),children:[jsxRuntimeExports.jsxs("span",{className:aphrodite.css(warningTextStyle),children:[warningText,":"," "]}),m]},i)),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$B.tail,tooltipAbove&&styles$B.tailAbove)})]})]})};}}const styles$B=aphrodite.StyleSheet.create({lintContainer:{position:"relative"},lintContainerBlock:{display:"block"},hoverTarget:{position:"absolute",top:0,right:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ div":{outline:"1px solid "+warningColor},":hover ~ div div[data-lint-inside-table]":{outline:"1px solid "+warningColor},":hover ~ div span[data-lint-inside-table]":{backgroundColor:warningColor,color:white}},inlineHoverTarget:{float:"right",position:"relative",marginRight:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ span":{backgroundColor:warningColor,color:white}},radioWidgetHoverTarget:{position:"absolute",left:-40,display:"block",width:24,height:24,minWidth:264,":hover > span":{backgroundColor:warningColorHover},":hover > div":{display:"block",padding:8,width:280},":hover > div > div":{left:8},":hover ~ span":{backgroundColor:warningColor,color:white}},indicator:{alignItems:"center",borderRadius:4,color:"white",display:"flex",fontSize:12,height:8,justifyContent:"center",margin:8,width:8},indicatorError:{backgroundColor:"#be2612",borderRadius:8,height:16,width:16},indicatorWarning:{backgroundColor:"#f86700"},indicatorGuideline:{backgroundColor:"#ffbe26"},tooltip:{position:"absolute",right:-12,display:"none",zIndex:1e3,color:white,backgroundColor:gray17,opacity:.9,fontFamily:baseFontFamily,fontSize:"12px",lineHeight:"15px",width:"320px",borderRadius:"4px"},tooltipAbove:{bottom:32},tail:{position:"absolute",top:-12,right:16,width:0,height:0,borderLeft:"8px solid transparent",borderRight:"8px solid transparent",borderBottom:"12px solid "+gray17},tailAbove:{bottom:-12,borderBottom:"none",borderTop:"12px solid "+gray17,top:"auto"},tooltipParagraph:{margin:12},warning:{color:warningColor,fontFamily:boldFontFamily},publishBlockingError:{color:publishBlockingErrorColor}});
1691
1691
 
1692
1692
  const rules={...pureMarkdown.pureMarkdownRules,columns:{...pureMarkdown.pureMarkdownRules.columns,react:(node,output,state)=>{return jsxRuntimeExports.jsxs("div",{className:"perseus-two-columns",children:[jsxRuntimeExports.jsx("div",{className:"perseus-column",children:jsxRuntimeExports.jsx("div",{className:"perseus-column-content",children:output(node.col1,state)})}),jsxRuntimeExports.jsx("div",{className:"perseus-column",children:jsxRuntimeExports.jsx("div",{className:"perseus-column-content",children:output(node.col2,state)})})]},state.key)}},crowdinId:{...pureMarkdown.pureMarkdownRules.crowdinId,react:(node,output,state)=>node.id},table:{...pureMarkdown.pureMarkdownRules.table,react:function(node,output,state){const table=SimpleMarkdown__default.default.defaultRules.table.react(node,output,state);if(!state.isMobile){return table}return React__namespace.cloneElement(table,{tabIndex:0})}},titledTable:{...pureMarkdown.pureMarkdownRules.titledTable,react:(node,output,state)=>{let contents;if(!node.table){contents="//invalid table//";}else if(node.table.type==="lint"){if(node.table.content?.type==="table"){contents=rules.lint.react({...node.table,content:{...node,table:node.table.content}},output,{...state,unwrapTitledTableContents:true});}else {contents=rules.lint.react(node.table,output,state);}}else {const tableOutput=SimpleMarkdown__default.default.defaultRules.table.react(node.table,output,state);const caption=jsxRuntimeExports.jsx("caption",{className:"perseus-table-title",children:output(node.title,state)},"caption");contents=React__namespace.cloneElement(tableOutput,null,[caption,...tableOutput.props.children]);}if(state.unwrapTitledTableContents){return contents}return jsxRuntimeExports.jsx("div",{className:"perseus-titled-table",children:contents},state.key)}},widget:{...pureMarkdown.pureMarkdownRules.widget,react:(node,output,state)=>{return jsxRuntimeExports.jsx("em",{children:`[Widget: ${node.id}]`},state.key)}},blockMath:{...pureMarkdown.pureMarkdownRules.blockMath,react:(node,output,state)=>{const{TeX}=getDependencies();return jsxRuntimeExports.jsx(TeX,{children:node.content},state.key)}},math:{...pureMarkdown.pureMarkdownRules.math,react:(node,output,state)=>{const{TeX}=getDependencies();return jsxRuntimeExports.jsx(TeX,{children:node.content},state.key)}},unescapedDollar:{...pureMarkdown.pureMarkdownRules.unescapedDollar,react:(node,output,state)=>{return "$"}},link:{...pureMarkdown.pureMarkdownRules.link,react:function(node,output,state){const link=SimpleMarkdown__default.default.defaultRules.link.react(node,output,state);const href=link.props.href;let rel=null;const isKAUrl=href?href.match(/https?:\/\/[^/]*khanacademy.org|^\//):false;if(!isKAUrl){rel="noopener noreferrer";}const newProps={...link.props,target:"_blank",href,rel};if(state.baseElements&&state.baseElements.Link){return state.baseElements.Link(newProps)}return React__namespace.cloneElement(link,newProps)}},codeBlock:{...pureMarkdown.pureMarkdownRules.codeBlock,react:(node,output,state)=>{if(node.lang==="alt"){return jsxRuntimeExports.jsx("div",{className:"perseus-markdown-alt perseus-sr-only",children:output(node.content,state)},state.key)}return SimpleMarkdown__default.default.defaultRules.codeBlock.react(node,output,state)}},lint:{...pureMarkdown.pureMarkdownRules.lint,react:(node,output,state)=>{return jsxRuntimeExports.jsx(Lint,{message:node.message,ruleName:node.ruleName,inline:isInline(node.content),blockHighlight:node.blockHighlight,insideTable:node.insideTable,severity:node.severity,children:output(node.content,state)})}}};function isInline(node){return !!(node&&node.type&&inlineNodeTypes.hasOwnProperty(node.type))}const inlineNodeTypes={text:true,math:true,unescapedDollar:true,link:true,img:true,strong:true,u:true,em:true,del:true,code:true};const builtParser=SimpleMarkdown__default.default.parserFor(rules);const parse$2=(source,state)=>{const paragraphedSource=source+"\n\n";return builtParser(paragraphedSource,{...state,inline:false})};const inlineParser=(source,state)=>{return builtParser(source,{...state,inline:true})};const getContent=ast=>{if(___default.default.isArray(ast)){return ___default.default.flatten(___default.default.map(ast,getContent))}if(ast.content&&___default.default.isString(ast.content)){if(ast.type.toLowerCase().indexOf("code")!==-1){return ["",ast.content,""]}return [ast.content.replace(/\s+/g," ")]}const children=___default.default.chain(ast).values().flatten().filter(object=>object!=null&&___default.default.has(object,"type")).value();if(!children.length){return []}const nestedContent=getContent(children);if(ast.type==="paragraph"&&nestedContent.length){nestedContent[0]=nestedContent[0].replace(/^\s+/,"");const last=nestedContent.length-1;nestedContent[last]=nestedContent[last].replace(/\s+$/,"");}return nestedContent};const characterCount=source=>{const ast=parse$2(source);const content=getContent(ast).join("");return content.length};var PerseusMarkdown = {characterCount:characterCount,traverseContent:pureMarkdown.traverseContent,parse:parse$2,parseInline:inlineParser,reactFor:SimpleMarkdown__default.default.reactFor,ruleOutput:SimpleMarkdown__default.default.ruleOutput(rules,"react"),basicOutput:SimpleMarkdown__default.default.reactFor(SimpleMarkdown__default.default.ruleOutput(rules,"react")),sanitizeUrl:SimpleMarkdown__default.default.sanitizeUrl};
1693
1693
 
@@ -1725,9 +1725,9 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
1725
1725
  supportsUngraded: supportsUngraded
1726
1726
  });
1727
1727
 
1728
- class WidgetContainer extends React__namespace.Component{componentDidMount(){if(this.props.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.")}}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})}const subType=getWidgetSubType(type,this.props.widgetProps)??"null";let alignment=this.props.widgetProps.alignment;if(alignment==="default"){alignment=perseusCore.CoreWidgetRegistry.getDefaultAlignment(type);}className+=perseusCore.CoreWidgetRegistry.getAlignmentClassName(type,alignment);const apiOptions=this.props.widgetProps.apiOptions;const isStatic=this.props.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,stack:error.stack??"No stack trace available",userAgent:userAgent}});},children:[jsxRuntimeExports.jsx(WidgetType,{...this.props.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},this.getWidget=()=>{return this.widgetRef.current};}}WidgetContainer.defaultProps={linterContext:PerseusLinter.linterContextDefault};
1728
+ class WidgetContainer extends React__namespace.Component{componentDidMount(){if(this.props.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.")}}render(){let className=classNames__default.default({"perseus-widget-container":true,"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})}const subType=getWidgetSubType(type,this.props.widgetProps)??"null";let alignment=this.props.widgetProps.alignment;if(alignment==="default"){alignment=perseusCore.CoreWidgetRegistry.getDefaultAlignment(type);}className+=perseusCore.CoreWidgetRegistry.getAlignmentClassName(type,alignment);const apiOptions=this.props.widgetProps.apiOptions;const isStatic=this.props.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,stack:error.stack??"No stack trace available",userAgent:userAgent}});},children:[jsxRuntimeExports.jsx(WidgetType,{...this.props.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},this.getWidget=()=>{return this.widgetRef.current};}}WidgetContainer.defaultProps={linterContext:PerseusLinter.linterContextDefault};
1729
1729
 
1730
- 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.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}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}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput&&!___default.default.isEqual(this.props.userInput,prevProps.userInput)){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}_isAnswerable(){if(this.props.userInput){return this.emptyWidgets().length===0}return false}_getWidgetIndexById(id){const widgetIndex=this.widgetIds.indexOf(id);if(widgetIndex<0){Log.error("Unable to get widget index in _getWidgetIndexById",perseusCore.Errors.Internal,{loggedMetadata:{widgets:JSON.stringify(this.props.widgets),widgetId:JSON.stringify(id)}});return 0}return widgetIndex}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.props.widgets[widgetId].options;const widgetInfo=this.state.widgetInfo[widgetId];if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,widgetIndex:this._getWidgetIndexById(widgetId),alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,graded:widgetInfo?.graded,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,showSolutions:this.props.showSolutions,onFocus:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewMode:this.props.reviewMode,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.apiOptions?.interactionCallback?.(updatedUserInput);},trackInteraction:interactionTracker.track}}getSerializedState(){return perseusCore.mapObject(this.props.widgets,(widgetData,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return widgetData.options})}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)}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();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});return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})})}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}},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;let shouldHighlight=false;if(this.props.highlightEmptyWidgets&&this.props.userInput){shouldHighlight=this.emptyWidgets().includes(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,widgetProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},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$z.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,{allowZoom:true,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$z.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)}});}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){const container=this._widgetContainers.get(makeContainerId(widgetId));if(container){return ReactDOM__namespace.default.findDOMNode(container)}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:[],...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},showSolutions:"none",onRender:noopOnRender,findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$z={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1730
+ 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.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}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}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput&&!___default.default.isEqual(this.props.userInput,prevProps.userInput)){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}_isAnswerable(){if(this.props.userInput){return this.emptyWidgets().length===0}return false}_getWidgetIndexById(id){const widgetIndex=this.widgetIds.indexOf(id);if(widgetIndex<0){Log.error("Unable to get widget index in _getWidgetIndexById",perseusCore.Errors.Internal,{loggedMetadata:{widgets:JSON.stringify(this.props.widgets),widgetId:JSON.stringify(id)}});return 0}return widgetIndex}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.props.widgets[widgetId].options;const widgetInfo=this.state.widgetInfo[widgetId];if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,widgetIndex:this._getWidgetIndexById(widgetId),alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,graded:widgetInfo?.graded,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,showSolutions:this.props.showSolutions,onFocus:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewMode:this.props.reviewMode,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.apiOptions?.interactionCallback?.(updatedUserInput);},trackInteraction:interactionTracker.track}}getSerializedState(){return perseusCore.mapObject(this.props.widgets,(widgetData,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return widgetData.options})}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)}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();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});return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})})}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}},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;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,widgetProps:this.getWidgetProps(id),linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},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$A.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,{allowZoom:true,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$A.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)}});}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){const container=this._widgetContainers.get(makeContainerId(widgetId));if(container){return ReactDOM__namespace.default.findDOMNode(container)}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:[],...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},showSolutions:"none",onRender:noopOnRender,findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$A={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
1731
1731
 
1732
1732
  const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=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]}
1733
1733
  ${props.examples.slice(1).join(", or\n")}`.replace(/\*/g,"").replace(/\$/g,"").replace(/\\ \\text{pi}/g," pi").replace(/\\ /g," 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$1,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}
@@ -1735,41 +1735,41 @@ const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;const Inp
1735
1735
 
1736
1736
  const getPromptJSON$p=widgetData=>{return {type:"numeric-input",label:widgetData.labelText,userInput:{value:widgetData.userInput.currentValue}}};
1737
1737
 
1738
- var styles$y = {"inputWithExamples":"perseus_QUlWSKE-","isFocused":"perseus_8i8MUC5K","rightAlign":"perseus_9cRSmuw9","sizeSmall":"perseus_LbMErCm0"};
1738
+ var styles$z = {"inputWithExamples":"perseus_QUlWSKE-","isFocused":"perseus_8i8MUC5K","rightAlign":"perseus_9cRSmuw9","sizeSmall":"perseus_LbMErCm0"};
1739
1739
 
1740
- const styles$x={inputWithExamples:{borderRadius:"0.3rem",borderWidth:"var(--wb-border-width-thin)",direction:"ltr",display:"inline-block",fontFamily:'Symbola, "Times New Roman", serif',fontSize:"1.8rem",height:"3.2rem",lineHeight:"1.8rem",padding:"0.4rem 0.5rem",textAlign:"left",width:"8rem"},isFocused:{borderWidth:"var(--wb-border-width-medium)",padding:"0.4rem"},rightAlign:{textAlign:"right"},sizeSmall:{width:"4rem"}};
1740
+ const styles$y={inputWithExamples:{borderRadius:"0.3rem",borderWidth:"var(--wb-border-width-thin)",direction:"ltr",display:"inline-block",fontFamily:'Symbola, "Times New Roman", serif',fontSize:"1.8rem",height:"3.2rem",lineHeight:"1.8rem",padding:"0.4rem 0.5rem",textAlign:"left",width:"8rem"},isFocused:{borderWidth:"var(--wb-border-width-medium)",padding:"0.4rem"},rightAlign:{textAlign:"right"},sizeSmall:{width:"4rem"}};
1741
1741
 
1742
1742
  const NumericExampleStrings={integer:(form,strings)=>strings.integerExample,proper:(form,strings)=>form.simplify==="optional"?strings.properExample:strings.simplifiedProperExample,improper:(form,strings)=>form.simplify==="optional"?strings.improperExample:strings.simplifiedImproperExample,mixed:(form,strings)=>strings.mixedExample,decimal:(form,strings)=>strings.decimalExample,percent:(form,strings)=>strings.percentExample,pi:(form,strings)=>strings.piExample};const generateExamples=(answerForms,strings)=>{if(answerForms.length===0){return []}const uniqueForms=getUniqueAnswerForms(answerForms);const examples=uniqueForms.map(form=>{return NumericExampleStrings[form.name](form,strings)});return [strings.yourAnswer].concat(examples)};const shouldShowExamples=answerForms=>{if(answerForms.length===0){return false}const answerFormNames=getUniqueAnswerForms(answerForms).map(form=>form.name);const allFormsAccepted=answerFormNames.length>=Object.keys(NumericExampleStrings).length;return !allFormsAccepted};const getUniqueAnswerForms=function(list){const foundForms=new Set;return list.filter(form=>{if(foundForms.has(form.name)){return false}foundForms.add(form.name);return true})};const unionAnswerForms=function(answerFormsList){const allForms=answerFormsList.flat();const uniqueForms=getUniqueAnswerForms(allForms);const formExampleKeys=Object.keys(NumericExampleStrings);return uniqueForms.sort((a,b)=>{return formExampleKeys.indexOf(a.name)-formExampleKeys.indexOf(b.name)})};function normalizeCorrectAnswerForms(answers){if(answers==null){return []}return unionAnswerForms(answers.filter(answer=>answer.status==="correct").map(answer=>{return (answer.answerForms||[]).map(form=>{return {simplify:answer.simplify,name:form}})}))}
1743
1743
 
1744
- const NumericInputComponent=React.forwardRef(function NumericInputComponent(props,ref){const{analytics}=useDependencies();const context=React.useContext(PerseusI18nContext);const inputRef=React.useRef(null);const[isFocused,setIsFocused]=React.useState(false);wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"numeric-input",widgetId:props.widgetId}});});React.useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current?.focus();setIsFocused(true);}},blur:()=>{if(inputRef.current){inputRef.current?.blur();setIsFocused(false);}}}));const handleChange=newValue=>{props.handleUserInput({currentValue:newValue});props.trackInteraction();};const handleFocus=()=>{props.onFocus([]);setIsFocused(true);};const handleBlur=()=>{props.onBlur([]);setIsFocused(false);};const legacyStylesToUse={...styles$x.inputWithExamples,...isFocused?styles$x.isFocused:{},...props.rightAlign?styles$x.rightAlign:{},...props.size==="small"?styles$x.sizeSmall:{}};const classesToUse=[styles$y.inputWithExamples];if(isFocused){classesToUse.push(styles$y.isFocused);}if(props.rightAlign){classesToUse.push(styles$y.rightAlign);}if(props.size==="small"){classesToUse.push(styles$y.sizeSmall);}if(props.apiOptions.customKeypad){const alignmentClass=props.rightAlign?"perseus-input-right-align":undefined;return jsxRuntimeExports.jsx("div",{className:alignmentClass,children:jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:inputRef,value:props.userInput.currentValue,keypadElement:props.keypadElement,onChange:handleChange,onFocus:handleFocus,onBlur:handleBlur})})}return jsxRuntimeExports.jsx(InputWithExamples,{ref:inputRef,value:props.userInput.currentValue,onChange:handleChange,labelText:props.labelText||context.strings.yourAnswerLabel,examples:generateExamples(props.answerForms,context.strings),shouldShowExamples:shouldShowExamples(props.answerForms),onFocus:handleFocus,onBlur:handleBlur,id:props.widgetId,disabled:props.apiOptions.readOnly,style:legacyStylesToUse,className:classesToUse.join(" ")})});
1744
+ const NumericInputComponent=React.forwardRef(function NumericInputComponent(props,ref){const{analytics}=useDependencies();const context=React.useContext(PerseusI18nContext);const inputRef=React.useRef(null);const[isFocused,setIsFocused]=React.useState(false);wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"numeric-input",widgetId:props.widgetId}});});React.useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current?.focus();setIsFocused(true);}},blur:()=>{if(inputRef.current){inputRef.current?.blur();setIsFocused(false);}}}));const handleChange=newValue=>{props.handleUserInput({currentValue:newValue});props.trackInteraction();};const handleFocus=()=>{props.onFocus([]);setIsFocused(true);};const handleBlur=()=>{props.onBlur([]);setIsFocused(false);};const legacyStylesToUse={...styles$y.inputWithExamples,...isFocused?styles$y.isFocused:{},...props.rightAlign?styles$y.rightAlign:{},...props.size==="small"?styles$y.sizeSmall:{}};const classesToUse=[styles$z.inputWithExamples];if(isFocused){classesToUse.push(styles$z.isFocused);}if(props.rightAlign){classesToUse.push(styles$z.rightAlign);}if(props.size==="small"){classesToUse.push(styles$z.sizeSmall);}if(props.apiOptions.customKeypad){const alignmentClass=props.rightAlign?"perseus-input-right-align":undefined;return jsxRuntimeExports.jsx("div",{className:alignmentClass,children:jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:inputRef,value:props.userInput.currentValue,keypadElement:props.keypadElement,onChange:handleChange,onFocus:handleFocus,onBlur:handleBlur})})}return jsxRuntimeExports.jsx(InputWithExamples,{ref:inputRef,value:props.userInput.currentValue,onChange:handleChange,labelText:props.labelText||context.strings.yourAnswerLabel,examples:generateExamples(props.answerForms,context.strings),shouldShowExamples:shouldShowExamples(props.answerForms),onFocus:handleFocus,onBlur:handleBlur,id:props.widgetId,disabled:props.apiOptions.readOnly,style:legacyStylesToUse,className:classesToUse.join(" ")})});
1745
1745
 
1746
1746
  class NumericInput extends React__namespace.Component{getPromptJSON(){return getPromptJSON$p(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.blur=()=>{this.inputRef.current?.blur();},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$i(){return {currentValue:""}}function getUserInputFromSerializedState$h(serializedState){return {currentValue:serializedState.currentValue}}function findPrecision(value){for(let i=0;i<10;i++){if(value===+value.toFixed(i)){return i}}return 10}function findCommonFractions(value){const whole=Math.floor(value);if(value===whole){return}const decimal=value-whole;const precision=findPrecision(decimal);for(let num=1;num<100;num++){for(let denom=2;denom<100;denom++){if(+(num/denom).toFixed(precision)===decimal){return {num:num+whole*denom,denom}}}}}function getCorrectUserInput$9(options){for(const answer of options.answers){if(answer.status==="correct"&&answer.value!=null){if(answer.answerForms?.includes("decimal")){return {currentValue:answer.value.toString()}}if(answer.answerForms?.includes("improper")){const frac=findCommonFractions(answer.value);if(frac){return {currentValue:`${frac.num}/${frac.denom}`}}}if(answer.answerForms?.includes("proper")){const frac=findCommonFractions(answer.value);if(frac){const{num,denom}=frac;if(num>denom){const whole=Math.floor(num/denom);const remainder=num-whole*denom;return {currentValue:`${whole} ${remainder}/${denom}`}}else {return {currentValue:`${num}/${denom}`}}}}return {currentValue:answer.value.toString()}}}return {currentValue:""}}var NumericInput$1 = {name:"numeric-input",displayName:"Numeric input",widget:NumericInput,isLintable:true,getCorrectUserInput: getCorrectUserInput$9,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$i,getUserInputFromSerializedState: getUserInputFromSerializedState$h};
1747
1747
 
1748
- const formExamples={integer:function(_,strings){return strings.integerExample},proper:function(options,strings){if(options.simplify==="optional"){return strings.properExample}return strings.simplifiedProperExample},improper:function(options,strings){if(options.simplify==="optional"){return strings.improperExample}return strings.simplifiedImproperExample},mixed:function(_,strings){return strings.mixedExample},decimal:function(_,strings){return strings.decimalExample},percent:function(_,strings){return strings.percentExample},pi:function(_,strings){return strings.piExample}};class InputNumber extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"input-number",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$q(this.props)}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){return {alignment:this.props.alignment,static:this.props.static,simplify:this.props.simplify,size:this.props.size,answerType:this.props.answerType,rightAlign:this.props.rightAlign,currentValue:this.props.userInput.currentValue}}render(){if(perseusCore.isFeatureOn(this.props,"input-number-to-numeric-input")){const numericInputOptions=perseusCore.convertInputNumberOptionsToNumericInput(this.props);return jsxRuntimeExports.jsx(NumericInput,{...this.props,...numericInputOptions,labelText:"",ref:this.handleInputRef})}if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:this.handleInputRef,value:this.props.userInput.currentValue,keypadElement:this.props.keypadElement,onChange:this.handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur});if(this.props.rightAlign){return jsxRuntimeExports.jsx("div",{className:"perseus-input-right-align",children:input})}return input}const inputStyles=[styles$w.default,this.props.size==="small"?styles$w.small:null,this.props.rightAlign?styles$w.rightAlign:styles$w.leftAlign];if(this.props.reviewMode&&!this.props.userInput.currentValue){inputStyles.push(styles$w.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:this.handleInputRef,value:this.props.userInput.currentValue,onChange:this.handleChange,style:inputStyles,examples:this.examples(),shouldShowExamples:this.shouldShowExamples(),onFocus:this._handleFocus,onBlur:this._handleBlur,id:this.props.widgetId,disabled:this.props.apiOptions.readOnly,linterContext:this.props.linterContext})}constructor(...args){super(...args),this.inputRef={current:null},this.handleInputRef=instance=>{this.inputRef.current=instance;},this.shouldShowExamples=()=>{return this.props.answerType!=="number"},this.handleChange=(newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);},this._handleFocus=()=>{this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{this.inputRef.current?.focus();return true},this.focusInputPath=()=>{this.inputRef.current?.focus();},this.blurInputPath=()=>{this.inputRef.current?.blur();},this.getInputPaths=()=>{return [[]]};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:{currentValue:""}};const styles$w=aphrodite.StyleSheet.create({default:{width:80,height:"auto",direction:"ltr"},small:{width:40},leftAlign:{paddingLeft:wonderBlocksTokens.spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:wonderBlocksTokens.spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}function getUserInputFromSerializedState$g(serializedState){return {currentValue:serializedState.currentValue}}function getStartUserInput$h(){return {currentValue:""}}function getCorrectUserInput$8(options){return {currentValue:options.value.toString()}}const WrappedInputNumber=withDependencies(InputNumber);var InputNumber$1 = {name:"input-number",displayName:"Input number (deprecated - use numeric input instead)",hidden:true,widget:WrappedInputNumber,isLintable:true,getOneCorrectAnswerFromRubric,getStartUserInput: getStartUserInput$h,getCorrectUserInput: getCorrectUserInput$8,getUserInputFromSerializedState: getUserInputFromSerializedState$g};
1748
+ const formExamples={integer:function(_,strings){return strings.integerExample},proper:function(options,strings){if(options.simplify==="optional"){return strings.properExample}return strings.simplifiedProperExample},improper:function(options,strings){if(options.simplify==="optional"){return strings.improperExample}return strings.simplifiedImproperExample},mixed:function(_,strings){return strings.mixedExample},decimal:function(_,strings){return strings.decimalExample},percent:function(_,strings){return strings.percentExample},pi:function(_,strings){return strings.piExample}};class InputNumber extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"input-number",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$q(this.props)}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){return {alignment:this.props.alignment,static:this.props.static,simplify:this.props.simplify,size:this.props.size,answerType:this.props.answerType,rightAlign:this.props.rightAlign,currentValue:this.props.userInput.currentValue}}render(){if(perseusCore.isFeatureOn(this.props,"input-number-to-numeric-input")){const numericInputOptions=perseusCore.convertInputNumberOptionsToNumericInput(this.props);return jsxRuntimeExports.jsx(NumericInput,{...this.props,...numericInputOptions,labelText:"",ref:this.handleInputRef})}if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:this.handleInputRef,value:this.props.userInput.currentValue,keypadElement:this.props.keypadElement,onChange:this.handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur});if(this.props.rightAlign){return jsxRuntimeExports.jsx("div",{className:"perseus-input-right-align",children:input})}return input}const inputStyles=[styles$x.default,this.props.size==="small"?styles$x.small:null,this.props.rightAlign?styles$x.rightAlign:styles$x.leftAlign];if(this.props.reviewMode&&!this.props.userInput.currentValue){inputStyles.push(styles$x.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:this.handleInputRef,value:this.props.userInput.currentValue,onChange:this.handleChange,style:inputStyles,examples:this.examples(),shouldShowExamples:this.shouldShowExamples(),onFocus:this._handleFocus,onBlur:this._handleBlur,id:this.props.widgetId,disabled:this.props.apiOptions.readOnly,linterContext:this.props.linterContext})}constructor(...args){super(...args),this.inputRef={current:null},this.handleInputRef=instance=>{this.inputRef.current=instance;},this.shouldShowExamples=()=>{return this.props.answerType!=="number"},this.handleChange=(newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);},this._handleFocus=()=>{this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{this.inputRef.current?.focus();return true},this.focusInputPath=()=>{this.inputRef.current?.focus();},this.blurInputPath=()=>{this.inputRef.current?.blur();},this.getInputPaths=()=>{return [[]]};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:{currentValue:""}};const styles$x=aphrodite.StyleSheet.create({default:{width:80,height:"auto",direction:"ltr"},small:{width:40},leftAlign:{paddingLeft:wonderBlocksTokens.spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:wonderBlocksTokens.spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}function getUserInputFromSerializedState$g(serializedState){return {currentValue:serializedState.currentValue}}function getStartUserInput$h(){return {currentValue:""}}function getCorrectUserInput$8(options){return {currentValue:options.value.toString()}}const WrappedInputNumber=withDependencies(InputNumber);var InputNumber$1 = {name:"input-number",displayName:"Input number (deprecated - use numeric input instead)",hidden:true,widget:WrappedInputNumber,isLintable:true,getOneCorrectAnswerFromRubric,getStartUserInput: getStartUserInput$h,getCorrectUserInput: getCorrectUserInput$8,getUserInputFromSerializedState: getUserInputFromSerializedState$g};
1749
1749
 
1750
1750
  const MathRenderingContext=React__namespace.createContext({shouldAddAriaLabels:false});
1751
1751
 
1752
1752
  const getPromptJSON$o=(widgetData,userInput)=>{const choices=widgetData.choices||[];const options=choices.map(choice=>{const option={value:choice.content,id:choice.id};if(choice.rationale){option.rationale=choice.rationale;}return option});const hasNoneOfTheAbove=choices.some(choice=>choice.isNoneOfTheAbove);return {type:"radio",hasNoneOfTheAbove,options,userInput:{selectedOptions:userInput?.selectedChoiceIds??[]}}};
1753
1753
 
1754
- var styles$v = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1754
+ var styles$w = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1755
1755
 
1756
- 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[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 contentIsRtl=getComputedStyle(containerRef.current).direction==="rtl";const scrollNegative=contentIsRtl&&direction==="end"||!contentIsRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});setTimeout(()=>{setIsScrolling(false);},150);},[isScrolling]);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;const newIsRtl=getComputedStyle(containerRef.current).direction==="rtl";const newIsScrollable=scrollWidth>clientWidth+scrollableThreshold;setIsScrollable(newIsScrollable);let newCanScrollStart;let newCanScrollEnd;if(newIsRtl){newCanScrollStart=scrollLeft<-scrollableThreshold;newCanScrollEnd=Math.abs(scrollLeft)<scrollWidth-clientWidth-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$v.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.scroll("start"),"aria-label":strings.scrollStart,disabled:!scrollState.canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:scrollState.isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:()=>scrollState.scroll("end"),"aria-label":strings.scrollEnd,disabled:!scrollState.canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",children:description})]})}const ScrollableView=ScrollableArea;ScrollableView.Controls=ScrollControls;
1756
+ 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[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 contentIsRtl=getComputedStyle(containerRef.current).direction==="rtl";const scrollNegative=contentIsRtl&&direction==="end"||!contentIsRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});setTimeout(()=>{setIsScrolling(false);},150);},[isScrolling]);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;const newIsRtl=getComputedStyle(containerRef.current).direction==="rtl";const newIsScrollable=scrollWidth>clientWidth+scrollableThreshold;setIsScrollable(newIsScrollable);let newCanScrollStart;let newCanScrollEnd;if(newIsRtl){newCanScrollStart=scrollLeft<-scrollableThreshold;newCanScrollEnd=Math.abs(scrollLeft)<scrollWidth-clientWidth-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$w.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.scroll("start"),"aria-label":strings.scrollStart,disabled:!scrollState.canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:scrollState.isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:()=>scrollState.scroll("end"),"aria-label":strings.scrollEnd,disabled:!scrollState.canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{size:"small",children:description})]})}const ScrollableView=ScrollableArea;ScrollableView.Controls=ScrollControls;
1757
1757
 
1758
- var styles$u = {"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"};
1758
+ var styles$v = {"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"};
1759
1759
 
1760
- const Indicator=props=>{const{checked,content,showCorrectness}=props;const indicatorId=React.useId();const ariaLabelledby=content.labelledBy?`${indicatorId} ${content.labelledBy}`:undefined;const ariaDisabled=showCorrectness?"true":"false";const iconImage=checked&&showCorrectness==="correct"?checkIcon__default.default:checked&&showCorrectness==="wrong"?minusIcon__default.default:undefined;const icon=iconImage?jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{"aria-hidden":true,className:styles$u.icon,icon:iconImage}):undefined;const classes=[styles$u.base,styles$u[props.shape+"-shape"]];if(showCorrectness){classes.push(styles$u["is-"+showCorrectness]);}const handleClick=showCorrectness?undefined:event=>{event.stopPropagation();props.updateChecked(!checked);};return jsxRuntimeExports.jsxs("button",{"aria-describedby":content.describedBy,"aria-disabled":ariaDisabled,"aria-pressed":checked,"aria-label":content.screenReader,"aria-labelledby":ariaLabelledby,className:classes.join(" "),id:indicatorId,type:"button",ref:props.buttonRef,onClick:handleClick,children:[icon,jsxRuntimeExports.jsx("span",{children:content.visible})]})};
1760
+ const Indicator=props=>{const{checked,content,showCorrectness}=props;const indicatorId=React.useId();const ariaLabelledby=content.labelledBy?`${indicatorId} ${content.labelledBy}`:undefined;const ariaDisabled=showCorrectness?"true":"false";const iconImage=checked&&showCorrectness==="correct"?checkIcon__default.default:checked&&showCorrectness==="wrong"?minusIcon__default.default:undefined;const icon=iconImage?jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{"aria-hidden":true,className:styles$v.icon,icon:iconImage}):undefined;const classes=[styles$v.base,styles$v[props.shape+"-shape"]];if(showCorrectness){classes.push(styles$v["is-"+showCorrectness]);}const handleClick=showCorrectness?undefined:event=>{event.stopPropagation();props.updateChecked(!checked);};return jsxRuntimeExports.jsxs("button",{"aria-describedby":content.describedBy,"aria-disabled":ariaDisabled,"aria-pressed":checked,"aria-label":content.screenReader,"aria-labelledby":ariaLabelledby,className:classes.join(" "),id:indicatorId,type:"button",ref:props.buttonRef,onClick:handleClick,children:[icon,jsxRuntimeExports.jsx("span",{children:content.visible})]})};
1761
1761
 
1762
- var styles$t = {"choice":"perseus_hm3uu-sq","is-correct":"perseus_qpU2z5U7","isCorrect":"perseus_qpU2z5U7","is-wrong":"perseus_dUXUrBDI","isWrong":"perseus_dUXUrBDI"};
1762
+ var styles$u = {"choice":"perseus_hm3uu-sq","is-correct":"perseus_qpU2z5U7","isCorrect":"perseus_qpU2z5U7","is-wrong":"perseus_dUXUrBDI","isWrong":"perseus_dUXUrBDI"};
1763
1763
 
1764
- const Choice=props=>{const showCorrectness=props.showCorrectness;const buttonRef=React.useRef(null);const indicatorShape=props.isMultiSelect?"square":"circle";const clickHandler=showCorrectness?undefined:()=>{buttonRef.current?.click();};const classes=[styles$t.choice].concat(showCorrectness?[styles$t["is-"+showCorrectness]]:[]).join(" ");return jsxRuntimeExports.jsxs("li",{className:classes,onClick:clickHandler,role:"listitem",children:[jsxRuntimeExports.jsx(Indicator,{buttonRef:buttonRef,checked:props.checked,content:props.indicatorContent,shape:indicatorShape,showCorrectness:showCorrectness,updateChecked:props.updateChecked}),props.children]})};
1764
+ const Choice=props=>{const showCorrectness=props.showCorrectness;const buttonRef=React.useRef(null);const indicatorShape=props.isMultiSelect?"square":"circle";const clickHandler=showCorrectness?undefined:()=>{buttonRef.current?.click();};const classes=[styles$u.choice].concat(showCorrectness?[styles$u["is-"+showCorrectness]]:[]).join(" ");return jsxRuntimeExports.jsxs("li",{className:classes,onClick:clickHandler,role:"listitem",children:[jsxRuntimeExports.jsx(Indicator,{buttonRef:buttonRef,checked:props.checked,content:props.indicatorContent,shape:indicatorShape,showCorrectness:showCorrectness,updateChecked:props.updateChecked}),props.children]})};
1765
1765
 
1766
- var styles$s = {"container":"perseus_yewUvpCl","choiceList":"perseus_ejJezW-c","content":"perseus_zAWs4E3G","instructions":"perseus_WyGpYl3q","rationale":"perseus_6vMrWVz0","isCorrect":"perseus_Zv66BVdg","reviewAnswers":"perseus_hJzSXKwq"};
1766
+ var styles$t = {"container":"perseus_yewUvpCl","choiceList":"perseus_ejJezW-c","content":"perseus_zAWs4E3G","instructions":"perseus_WyGpYl3q","rationale":"perseus_6vMrWVz0","isCorrect":"perseus_Zv66BVdg","reviewAnswers":"perseus_hJzSXKwq"};
1767
1767
 
1768
1768
  function getChoiceLetter(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}function hasChoiceData(state){return state!=null&&typeof state==="object"&&"choiceStates"in state&&"choices"in state&&Array.isArray(state.choiceStates)&&Array.isArray(state.choices)}function getUserInputFromSerializedState$f(serializedState){const selectedChoiceIds=[];if(hasChoiceData(serializedState)){const{choiceStates,choices}=serializedState;for(let i=0;i<choiceStates.length;i++){const choiceState=choiceStates[i];const choice=choices[i];if(choiceState?.selected&&choice?.id){selectedChoiceIds.push(choice.id);}}}return {selectedChoiceIds}}function moveNoneOfTheAboveToEnd(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices}function enforceOrdering(choices,strings){const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>___default.default.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices}function choiceTransform(choices,randomize,strings,seed){const choicesWithMetadata=choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return moveNoneOfTheAboveToEnd(enforceOrdering(randomize?perseusCore.shuffle(choicesWithMetadata,seed):choicesWithMetadata,strings))}
1769
1769
 
1770
1770
  const 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};
1771
1771
 
1772
- const RadioComponent=({choices,countChoices,multipleSelect=false,numCorrect,onChoiceChange,reviewMode})=>{const{strings}=usePerseusI18n();const legendId=React.useId();const containerRef=React.useRef(null);const[backgroundColor,setBackgroundColor]=React.useState("transparent");React.useEffect(()=>{const container=containerRef.current;if(container){setBackgroundColor(getBackgroundColor(container));}},[]);wonderBlocksTiming.useTimeout(()=>{const container=containerRef.current;if(container){setBackgroundColor(getBackgroundColor(container));}},100);const instructions=getInstructionsText({multipleSelect,countChoices,numCorrect,strings});const choiceListClasses=reviewMode?`${styles$s.choiceList} ${styles$s.reviewAnswers}`:styles$s.choiceList;const cssVariableDeclaration=backgroundColor!=="transparent"?{"--perseus-widget-background-color":backgroundColor}:undefined;const scrollId=React.useId()+"-scroll";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("fieldset",{className:styles$s.container,ref:containerRef,style:cssVariableDeclaration,children:[jsxRuntimeExports.jsx("legend",{id:legendId,"aria-hidden":"true",className:styles$s.instructions,children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{id:scrollId,overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{"data-widget":"radio","aria-labelledby":legendId,className:choiceListClasses,role:"list",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$s.rationale} ${styles$s.isCorrect}`:styles$s.rationale;rationale=jsxRuntimeExports.jsx("div",{id:rationaleId,className:rationaleClasses,children:choice.rationale});}return jsxRuntimeExports.jsx(Choice,{checked:choice.checked,indicatorContent:indicatorContent,isMultiSelect:multipleSelect,showCorrectness:showCorrectness,updateChecked:updateChecked,children:jsxRuntimeExports.jsxs("div",{className:styles$s.content,children:[jsxRuntimeExports.jsx("div",{id:contentId,children:content}),rationale]})},choice.id)});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:items})};
1772
+ const RadioComponent=({choices,countChoices,multipleSelect=false,numCorrect,onChoiceChange,reviewMode})=>{const{strings}=usePerseusI18n();const legendId=React.useId();const containerRef=React.useRef(null);const[backgroundColor,setBackgroundColor]=React.useState("transparent");React.useEffect(()=>{const container=containerRef.current;if(container){setBackgroundColor(getBackgroundColor(container));}},[]);wonderBlocksTiming.useTimeout(()=>{const container=containerRef.current;if(container){setBackgroundColor(getBackgroundColor(container));}},100);const instructions=getInstructionsText({multipleSelect,countChoices,numCorrect,strings});const choiceListClasses=reviewMode?`${styles$t.choiceList} ${styles$t.reviewAnswers}`:styles$t.choiceList;const cssVariableDeclaration=backgroundColor!=="transparent"?{"--perseus-widget-background-color":backgroundColor}:undefined;const scrollId=React.useId()+"-scroll";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("fieldset",{className:styles$t.container,ref:containerRef,style:cssVariableDeclaration,children:[jsxRuntimeExports.jsx("legend",{id:legendId,"aria-hidden":"true",className:styles$t.instructions,children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{id:scrollId,overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{"data-widget":"radio","aria-labelledby":legendId,className:choiceListClasses,role:"list",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$t.rationale} ${styles$t.isCorrect}`:styles$t.rationale;rationale=jsxRuntimeExports.jsx("div",{id:rationaleId,className:rationaleClasses,children:choice.rationale});}return jsxRuntimeExports.jsx(Choice,{checked:choice.checked,indicatorContent:indicatorContent,isMultiSelect:multipleSelect,showCorrectness:showCorrectness,updateChecked:updateChecked,children:jsxRuntimeExports.jsxs("div",{className:styles$t.content,children:[jsxRuntimeExports.jsx("div",{id:contentId,children:content}),rationale]})},choice.id)});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:items})};
1773
1773
 
1774
1774
  const getChoiceStates=({choices,showSolutions,choiceStates,reviewMode})=>{if(showSolutions==="all"||reviewMode){return choices.map(choice=>({selected:!!choice.correct}))}if(choiceStates){return choiceStates}return choices.map(()=>({selected:false}))};
1775
1775
 
@@ -1785,7 +1785,7 @@ const{radioBorderColor,checkedColor,circleSize,radioMarginWidth}=constants;var s
1785
1785
 
1786
1786
  const getPromptJSON$n=widgetData=>{return {type:"categorizer",options:{items:widgetData.items,categories:widgetData.categories},userInput:{itemToCategoryMapping:widgetData.userInput.values}}};
1787
1787
 
1788
- class Categorizer extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"categorizer",widgetId:this.props.widgetId}});}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,values:userInput.values}}getPromptJSON(){return getPromptJSON$n(this.props)}_handleUserInput(itemNum,catNum){const values=[...this.props.userInput.values];values[itemNum]=catNum;this.props.handleUserInput({values});this.props.trackInteraction();}render(){const self=this;const isMobile=this.props.apiOptions.isMobile;let indexedItems=this.props.items.map((item,n)=>[item,n]);if(this.props.randomizeItems){indexedItems=perseusCore.shuffle(indexedItems,this.props.problemNum);}const table=jsxRuntimeExports.jsxs("table",{className:"categorizer-table "+aphrodite.css(styles$r.mobileTable),children:[jsxRuntimeExports.jsx("thead",{children:jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$r.emptyHeaderCell)}),this.props.categories.map((category,i)=>{return jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$r.header),children:jsxRuntimeExports.jsx(Renderer,{content:category,linterContext:this.props.linterContext,strings:this.context.strings})},i)})]})}),jsxRuntimeExports.jsx("tbody",{children:indexedItems.map(indexedItem=>{const item=indexedItem[0];const itemNum=indexedItem[1];const uniqueId=self.state.uniqueId+"_"+itemNum;return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(Renderer,{content:item,linterContext:this.props.linterContext,strings:this.context.strings})}),self.props.categories.map((catName,catNum)=>{const selected=self.props.userInput.values[itemNum]===catNum;return jsxRuntimeExports.jsx("td",{className:"category "+aphrodite.css(styles$r.cell),children:jsxRuntimeExports.jsxs("div",{role:"button","aria-label":catName,onClick:()=>this._handleUserInput(itemNum,catNum),children:[isMobile&&jsxRuntimeExports.jsx("input",{type:"radio",name:uniqueId,className:aphrodite.css(sharedStyles.responsiveInput,sharedStyles.responsiveRadioInput),checked:selected,onChange:()=>this._handleUserInput(itemNum,catNum),onClick:e=>e.stopPropagation()}),!isMobile&&jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$r.radioSpan,selected&&styles$r.checkedRadioSpan,this.props.static&&selected&&styles$r.staticCheckedRadioSpan),children:selected?jsxRuntimeExports.jsx(InlineIcon,{...iconCircle}):jsxRuntimeExports.jsx(InlineIcon,{...iconCircleThin})})]})},catNum)})]},itemNum)})})]});const extraClassNames=classNames__default.default({"categorizer-container":true,"static-mode":this.props.static});const inlineStyles=this.props.apiOptions.isMobile?[styles$r.fullBleedContainer]:[];return jsxRuntimeExports.jsx("div",{className:extraClassNames+" "+aphrodite.css(...inlineStyles),children:table})}constructor(...args){super(...args),this.state={uniqueId:___default.default.uniqueId("perseus_radio_")};}}Categorizer.contextType=PerseusI18nContext;Categorizer.defaultProps={items:[],categories:[],linterContext:PerseusLinter.linterContextDefault,userInput:{values:[]}};const styles$r=aphrodite.StyleSheet.create({mobileTable:{[mediaQueries.smOrSmaller]:{minWidth:"auto"}},fullBleedContainer:{[mediaQueries.mdOrSmaller]:{marginLeft:-16,marginRight:-16,overflowX:"auto"}},header:{textAlign:"center",verticalAlign:"bottom"},cell:{textAlign:"center",padding:0,color:"#ccc",verticalAlign:"middle"},emptyHeaderCell:{backgroundColor:"inherit",borderBottom:"2px solid #ccc"},radioSpan:{fontSize:30,paddingRight:3,":hover":{color:"#999"}},checkedRadioSpan:{color:"#333"},staticCheckedRadioSpan:{color:"#888"}});function getUserInputFromSerializedState$e(serializedState){return {values:serializedState.values}}function getCorrectUserInput$7(options){return {values:options.values}}function getStartUserInput$f(){return {values:[]}}const WrappedCategorizer=withDependencies(Categorizer);var Categorizer$1 = {name:"categorizer",displayName:"Categorizer",hidden:true,widget:WrappedCategorizer,getUserInputFromSerializedState: getUserInputFromSerializedState$e,getCorrectUserInput: getCorrectUserInput$7,getStartUserInput: getStartUserInput$f,isLintable:true};
1788
+ class Categorizer extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"categorizer",widgetId:this.props.widgetId}});}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,values:userInput.values}}getPromptJSON(){return getPromptJSON$n(this.props)}_handleUserInput(itemNum,catNum){const values=[...this.props.userInput.values];values[itemNum]=catNum;this.props.handleUserInput({values});this.props.trackInteraction();}render(){const self=this;const isMobile=this.props.apiOptions.isMobile;let indexedItems=this.props.items.map((item,n)=>[item,n]);if(this.props.randomizeItems){indexedItems=perseusCore.shuffle(indexedItems,this.props.problemNum);}const table=jsxRuntimeExports.jsxs("table",{className:"categorizer-table "+aphrodite.css(styles$s.mobileTable),children:[jsxRuntimeExports.jsx("thead",{children:jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$s.emptyHeaderCell)}),this.props.categories.map((category,i)=>{return jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$s.header),children:jsxRuntimeExports.jsx(Renderer,{content:category,linterContext:this.props.linterContext,strings:this.context.strings})},i)})]})}),jsxRuntimeExports.jsx("tbody",{children:indexedItems.map(indexedItem=>{const item=indexedItem[0];const itemNum=indexedItem[1];const uniqueId=self.state.uniqueId+"_"+itemNum;return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(Renderer,{content:item,linterContext:this.props.linterContext,strings:this.context.strings})}),self.props.categories.map((catName,catNum)=>{const selected=self.props.userInput.values[itemNum]===catNum;return jsxRuntimeExports.jsx("td",{className:"category "+aphrodite.css(styles$s.cell),children:jsxRuntimeExports.jsxs("div",{role:"button","aria-label":catName,onClick:()=>this._handleUserInput(itemNum,catNum),children:[isMobile&&jsxRuntimeExports.jsx("input",{type:"radio",name:uniqueId,className:aphrodite.css(sharedStyles.responsiveInput,sharedStyles.responsiveRadioInput),checked:selected,onChange:()=>this._handleUserInput(itemNum,catNum),onClick:e=>e.stopPropagation()}),!isMobile&&jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$s.radioSpan,selected&&styles$s.checkedRadioSpan,this.props.static&&selected&&styles$s.staticCheckedRadioSpan),children:selected?jsxRuntimeExports.jsx(InlineIcon,{...iconCircle}):jsxRuntimeExports.jsx(InlineIcon,{...iconCircleThin})})]})},catNum)})]},itemNum)})})]});const extraClassNames=classNames__default.default({"categorizer-container":true,"static-mode":this.props.static});const inlineStyles=this.props.apiOptions.isMobile?[styles$s.fullBleedContainer]:[];return jsxRuntimeExports.jsx("div",{className:extraClassNames+" "+aphrodite.css(...inlineStyles),children:table})}constructor(...args){super(...args),this.state={uniqueId:___default.default.uniqueId("perseus_radio_")};}}Categorizer.contextType=PerseusI18nContext;Categorizer.defaultProps={items:[],categories:[],linterContext:PerseusLinter.linterContextDefault,userInput:{values:[]}};const styles$s=aphrodite.StyleSheet.create({mobileTable:{[mediaQueries.smOrSmaller]:{minWidth:"auto"}},fullBleedContainer:{[mediaQueries.mdOrSmaller]:{marginLeft:-16,marginRight:-16,overflowX:"auto"}},header:{textAlign:"center",verticalAlign:"bottom"},cell:{textAlign:"center",padding:0,color:"#ccc",verticalAlign:"middle"},emptyHeaderCell:{backgroundColor:"inherit",borderBottom:"2px solid #ccc"},radioSpan:{fontSize:30,paddingRight:3,":hover":{color:"#999"}},checkedRadioSpan:{color:"#333"},staticCheckedRadioSpan:{color:"#888"}});function getUserInputFromSerializedState$e(serializedState){return {values:serializedState.values}}function getCorrectUserInput$7(options){return {values:options.values}}function getStartUserInput$f(){return {values:[]}}const WrappedCategorizer=withDependencies(Categorizer);var Categorizer$1 = {name:"categorizer",displayName:"Categorizer",hidden:true,widget:WrappedCategorizer,getUserInputFromSerializedState: getUserInputFromSerializedState$e,getCorrectUserInput: getCorrectUserInput$7,getStartUserInput: getStartUserInput$f,isLintable:true};
1789
1789
 
1790
1790
  const isFileProtocol=protocol=>{if(protocol&&protocol.toLowerCase()==="file:"){return true}return false};
1791
1791
 
@@ -1795,15 +1795,15 @@ const getUnsupportedPromptJSON=(widgetType,message="")=>{return {type:widgetType
1795
1795
 
1796
1796
  const getPromptJSON$m=()=>{return getUnsupportedPromptJSON("cs-program")};
1797
1797
 
1798
- const{updateQueryString: updateQueryString$1}=Util;function getUrlFromProgramID$1(programID){const{InitialRequestUrl}=getDependencies();const path="/computer-programming/program/"+`${programID}/embedded?embed=yes&author=no`;if(isFileProtocol(InitialRequestUrl.protocol)){return `https://khanacademy.org${path}`}return toAbsoluteUrl(path)}class CSProgram extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$m()}getSerializedState(){const{userInput:_,alignment:__,...rest}=this.props;return {...rest,programType:rest.programType||null}}render(){if(!this.props.programID){return jsxRuntimeExports.jsx("div",{})}let styleContainer=false;let url=getUrlFromProgramID$1(this.props.programID);let className;const style={height:this.props.height,width:"100%"};if(this.props.showEditor){url+="&editor=yes";className="perseus-scratchpad-editor";}else {url+=`&editor=no&width=${articleMaxWidthInPx}`;className="perseus-scratchpad";if(this.props.programType!=="webpage"){styleContainer=true;}}if(this.props.showButtons){url+="&buttons=yes";style.height+=67;}else {url+="&buttons=no";}if(this.props.settings){const settings={};___default.default.each(this.props.settings,function(setting){if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString$1(url,"settings",JSON.stringify(settings));}if(this.context?.locale){url=updateQueryString$1(url,"lang",this.context.locale);}const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styleContainer&&styles$q.container),children:jsxRuntimeExports.jsx("iframe",{title:this.context.strings.computerScienceProgram,sandbox:sandboxOptions,src:url,style:style,className:className,allowFullScreen:true})})}constructor(...args){super(...args),this.handleMessageEvent=e=>{let data={};try{data=JSON.parse(e.originalEvent.data);}catch{return}if(___default.default.isUndefined(data.testsPassed)){return}const status=data.testsPassed?"correct":"incorrect";this.props.handleUserInput({status:status,message:data.message});};}}CSProgram.contextType=PerseusI18nContext;CSProgram.defaultProps={showEditor:false,showButtons:false,userInput:{status:"incomplete",message:null}};const styles$q=aphrodite.StyleSheet.create({container:{margin:"auto"}});function getUserInputFromSerializedState$d(serializedState){return {status:serializedState.status,message:serializedState.message}}function getStartUserInput$e(){return {status:"incomplete",message:null}}var CSProgram$1 = {name:"cs-program",displayName:"CS Program",widget:CSProgram,hidden:true,getStartUserInput: getStartUserInput$e,getUserInputFromSerializedState: getUserInputFromSerializedState$d};
1798
+ const{updateQueryString: updateQueryString$1}=Util;function getUrlFromProgramID$1(programID){const{InitialRequestUrl}=getDependencies();const path="/computer-programming/program/"+`${programID}/embedded?embed=yes&author=no`;if(isFileProtocol(InitialRequestUrl.protocol)){return `https://khanacademy.org${path}`}return toAbsoluteUrl(path)}class CSProgram extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$m()}getSerializedState(){const{userInput:_,alignment:__,...rest}=this.props;return {...rest,programType:rest.programType||null}}render(){if(!this.props.programID){return jsxRuntimeExports.jsx("div",{})}let styleContainer=false;let url=getUrlFromProgramID$1(this.props.programID);let className;const style={height:this.props.height,width:"100%"};if(this.props.showEditor){url+="&editor=yes";className="perseus-scratchpad-editor";}else {url+=`&editor=no&width=${articleMaxWidthInPx}`;className="perseus-scratchpad";if(this.props.programType!=="webpage"){styleContainer=true;}}if(this.props.showButtons){url+="&buttons=yes";style.height+=67;}else {url+="&buttons=no";}if(this.props.settings){const settings={};___default.default.each(this.props.settings,function(setting){if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString$1(url,"settings",JSON.stringify(settings));}if(this.context?.locale){url=updateQueryString$1(url,"lang",this.context.locale);}const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styleContainer&&styles$r.container),children:jsxRuntimeExports.jsx("iframe",{title:this.context.strings.computerScienceProgram,sandbox:sandboxOptions,src:url,style:style,className:className,allowFullScreen:true})})}constructor(...args){super(...args),this.handleMessageEvent=e=>{let data={};try{data=JSON.parse(e.originalEvent.data);}catch{return}if(___default.default.isUndefined(data.testsPassed)){return}const status=data.testsPassed?"correct":"incorrect";this.props.handleUserInput({status:status,message:data.message});};}}CSProgram.contextType=PerseusI18nContext;CSProgram.defaultProps={showEditor:false,showButtons:false,userInput:{status:"incomplete",message:null}};const styles$r=aphrodite.StyleSheet.create({container:{margin:"auto"}});function getUserInputFromSerializedState$d(serializedState){return {status:serializedState.status,message:serializedState.message}}function getStartUserInput$e(){return {status:"incomplete",message:null}}var CSProgram$1 = {name:"cs-program",displayName:"CS Program",widget:CSProgram,hidden:true,getStartUserInput: getStartUserInput$e,getUserInputFromSerializedState: getUserInputFromSerializedState$d};
1799
1799
 
1800
1800
  const getPromptJSON$l=widgetData=>{return {type:"definition",definition:widgetData.definition,togglePrompt:widgetData.togglePrompt}};
1801
1801
 
1802
- var styles$p = {"definition":"perseus_5CDFHduT"};
1802
+ var styles$q = {"definition":"perseus_5CDFHduT"};
1803
1803
 
1804
- const styles$o={tooltipBody:{color:"var(--wb-semanticColor-core-foreground-neutral-strong)",fontSize:"var(--wb-font-body-size-medium)",fontWeight:"var(--wb-font-weight-medium)",lineHeight:"var(--wb-font-body-lineHeight-medium)"}};
1804
+ const styles$p={tooltipBody:{color:"var(--wb-semanticColor-core-foreground-neutral-strong)",fontSize:"var(--wb-font-body-size-medium)",fontWeight:"var(--wb-font-weight-medium)",lineHeight:"var(--wb-font-body-lineHeight-medium)"}};
1805
1805
 
1806
- class Definition extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"definition",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$l(this.props)}render(){return jsxRuntimeExports.jsx(DefinitionConsumer,{children:({activeDefinitionId,setActiveDefinitionId})=>jsxRuntimeExports.jsx(wonderBlocksPopover.Popover,{dismissEnabled:true,content:jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$o.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);},"aria-label":this.context.strings.definitionIdentifier({word:this.props.togglePrompt}),children:()=>jsxRuntimeExports.jsx("span",{className:styles$p.definition,children:this.props.togglePrompt})})})})}constructor(...args){super(...args),this.isWidget=true;}}Definition.contextType=PerseusI18nContext;Definition.defaultProps={togglePrompt:"define me",definition:"definition goes here"};const WrappedDefinition=withDependencies(Definition);var Definition$1 = {name:"definition",displayName:"Definition",widget:WrappedDefinition};
1806
+ class Definition extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"definition",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$l(this.props)}render(){return jsxRuntimeExports.jsx(DefinitionConsumer,{children:({activeDefinitionId,setActiveDefinitionId})=>jsxRuntimeExports.jsx(wonderBlocksPopover.Popover,{dismissEnabled:true,content:jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$p.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);},"aria-label":this.context.strings.definitionIdentifier({word:this.props.togglePrompt}),children:()=>jsxRuntimeExports.jsx("span",{className:styles$q.definition,children:this.props.togglePrompt})})})})}constructor(...args){super(...args),this.isWidget=true;}}Definition.contextType=PerseusI18nContext;Definition.defaultProps={togglePrompt:"define me",definition:"definition goes here"};const WrappedDefinition=withDependencies(Definition);var Definition$1 = {name:"definition",displayName:"Definition",widget:WrappedDefinition};
1807
1807
 
1808
1808
  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};
1809
1809
 
@@ -1815,31 +1815,31 @@ function sharedInitializeUserInput(widgetOptions,problemNum){const startUserInpu
1815
1815
 
1816
1816
  const getPromptJSON$j=widgetData=>{return {type:"explanation",showPrompt:widgetData.showPrompt,explanation:widgetData.explanation}};
1817
1817
 
1818
- var styles$n = {"content":"perseus_HDIlPzEz","contentCollapsed":"perseus_NkFQFgcZ","contentExpanded":"perseus_XhV-9haB","contentWrapper":"perseus_WEJESS6h","transitionCollapsed":"perseus_sbBrAODD","transitionExpanded":"perseus_Wp72j6qk"};
1818
+ var styles$o = {"content":"perseus_HDIlPzEz","contentCollapsed":"perseus_NkFQFgcZ","contentExpanded":"perseus_XhV-9haB","contentWrapper":"perseus_WEJESS6h","transitionCollapsed":"perseus_sbBrAODD","transitionExpanded":"perseus_Wp72j6qk"};
1819
1819
 
1820
- const styles$m={buttonStyleOverrides:{height:"auto",lineHeight:"inherit",marginLeft:"-0.2rem",marginRight:"0.2rem",paddingLeft:"0.2rem"},content:{borderLeft:"0px solid #ccc",display:"inline-grid",position:"relative"},contentCollapsed:{gridTemplateColumns:"0fr",gridTemplateRows:"0fr",marginBottom:"0",marginTop:"0",minWidth:"0",paddingBottom:"0",visibility:"hidden"},contentExpanded:{borderLeftWidth:"5px",gridTemplateColumns:"1fr",gridTemplateRows:"1fr",marginBottom:"1.4rem",marginLeft:"-2.3rem",marginTop:"1.4rem",minWidth:"100%",paddingBottom:"1rem",paddingLeft:"2.3rem",visibility:"visible"},contentWrapper:{overflow:"hidden"},labelStyle:{fontSize:"var(--wb-font-heading-size-medium)",lineHeight:"inherit",marginRight:"-0.6rem",textAlign:"left",whiteSpace:"normal"},transitionCollapsed:{transition:"all 0.25s step-end, grid-template-rows 0.25s, margin-top 0.25s, margin-bottom 0.25s, padding-bottom 0.25s"},transitionExpanded:{transition:"grid-template-rows 0.5s, margin-top 0.5s, margin-bottom 0.5s, padding-bottom 0.5s"}};
1820
+ const styles$n={buttonStyleOverrides:{height:"auto",lineHeight:"inherit",marginLeft:"-0.2rem",marginRight:"0.2rem",paddingLeft:"0.2rem"},content:{borderLeft:"0px solid #ccc",display:"inline-grid",position:"relative"},contentCollapsed:{gridTemplateColumns:"0fr",gridTemplateRows:"0fr",marginBottom:"0",marginTop:"0",minWidth:"0",paddingBottom:"0",visibility:"hidden"},contentExpanded:{borderLeftWidth:"5px",gridTemplateColumns:"1fr",gridTemplateRows:"1fr",marginBottom:"1.4rem",marginLeft:"-2.3rem",marginTop:"1.4rem",minWidth:"100%",paddingBottom:"1rem",paddingLeft:"2.3rem",visibility:"visible"},contentWrapper:{overflow:"hidden"},labelStyle:{fontSize:"var(--wb-font-heading-size-medium)",lineHeight:"inherit",marginRight:"-0.6rem",textAlign:"left",whiteSpace:"normal"},transitionCollapsed:{transition:"all 0.25s step-end, grid-template-rows 0.25s, margin-top 0.25s, margin-bottom 0.25s, padding-bottom 0.25s"},transitionExpanded:{transition:"grid-template-rows 0.5s, margin-top 0.5s, margin-bottom 0.5s, padding-bottom 0.5s"}};
1821
1821
 
1822
- function mediaQueryIsMatched(mediaQuery){if(typeof window.matchMedia!=="function"){return false}return window.matchMedia(mediaQuery).matches}class Explanation extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"explanation",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$j(this.props)}render(){const promptText=this.state.expanded?this.props.hidePrompt:this.props.showPrompt;const caretIcon=this.state.expanded?caretUp__default.default:caretDown__default.default;const legacyContentStyling=[styles$m.content,this.state.expanded?styles$m.contentExpanded:styles$m.contentCollapsed,mediaQueryIsMatched("(prefers-reduced-motion: no-preference)")&&(this.state.expanded?styles$m.transitionExpanded:styles$m.transitionCollapsed)];const contentClasses=[styles$n.content,this.state.expanded?styles$n.contentExpanded:styles$n.contentCollapsed,this.state.expanded?styles$n.transitionExpanded:styles$n.transitionCollapsed];return jsxRuntimeExports.jsx(wonderBlocksCore.Id,{children:contentId=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button__default.default,{"aria-expanded":this.state.expanded,"aria-controls":contentId,endIcon:caretIcon,kind:"tertiary",labelStyle:styles$m.labelStyle,onClick:this._onClick,size:"small",style:styles$m.buttonStyleOverrides,children:promptText}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:contentId,style:legacyContentStyling,className:contentClasses.join(" "),"aria-hidden":!this.state.expanded,testId:"content-container",children:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:styles$n.contentWrapper,style:styles$m.contentWrapper,children:jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>{return jsxRuntimeExports.jsx(Renderer,{apiOptions:this.props.apiOptions,content:this.props.explanation,widgets:this.props.widgets,linterContext:this.props.linterContext,strings:this.context.strings,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput})}})})})]})})}constructor(...args){super(...args),this.isWidget=true,this.state={expanded:false},this._onClick=()=>{this.setState({expanded:!this.state.expanded});this.props.trackInteraction();};}}Explanation.contextType=PerseusI18nContext;Explanation.defaultProps={showPrompt:"Explain",hidePrompt:"Hide explanation",explanation:"explanation goes here\n\nmore explanation",widgets:{},linterContext:PerseusLinter.linterContextDefault};const WrappedExplanation=withDependencies(Explanation);var Explanation$1 = {name:"explanation",displayName:"Explanation",widget:WrappedExplanation,isLintable:true};
1822
+ function mediaQueryIsMatched(mediaQuery){if(typeof window.matchMedia!=="function"){return false}return window.matchMedia(mediaQuery).matches}class Explanation extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"explanation",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$j(this.props)}render(){const promptText=this.state.expanded?this.props.hidePrompt:this.props.showPrompt;const caretIcon=this.state.expanded?caretUp__default.default:caretDown__default.default;const legacyContentStyling=[styles$n.content,this.state.expanded?styles$n.contentExpanded:styles$n.contentCollapsed,mediaQueryIsMatched("(prefers-reduced-motion: no-preference)")&&(this.state.expanded?styles$n.transitionExpanded:styles$n.transitionCollapsed)];const contentClasses=[styles$o.content,this.state.expanded?styles$o.contentExpanded:styles$o.contentCollapsed,this.state.expanded?styles$o.transitionExpanded:styles$o.transitionCollapsed];return jsxRuntimeExports.jsx(wonderBlocksCore.Id,{children:contentId=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button__default.default,{"aria-expanded":this.state.expanded,"aria-controls":contentId,endIcon:caretIcon,kind:"tertiary",labelStyle:styles$n.labelStyle,onClick:this._onClick,size:"small",style:styles$n.buttonStyleOverrides,children:promptText}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:contentId,style:legacyContentStyling,className:contentClasses.join(" "),"aria-hidden":!this.state.expanded,testId:"content-container",children:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:styles$o.contentWrapper,style:styles$n.contentWrapper,children:jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>{return jsxRuntimeExports.jsx(Renderer,{apiOptions:this.props.apiOptions,content:this.props.explanation,widgets:this.props.widgets,linterContext:this.props.linterContext,strings:this.context.strings,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput})}})})})]})})}constructor(...args){super(...args),this.isWidget=true,this.state={expanded:false},this._onClick=()=>{this.setState({expanded:!this.state.expanded});this.props.trackInteraction();};}}Explanation.contextType=PerseusI18nContext;Explanation.defaultProps={showPrompt:"Explain",hidePrompt:"Hide explanation",explanation:"explanation goes here\n\nmore explanation",widgets:{},linterContext:PerseusLinter.linterContextDefault};const WrappedExplanation=withDependencies(Explanation);var Explanation$1 = {name:"explanation",displayName:"Explanation",widget:WrappedExplanation,isLintable:true};
1823
1823
 
1824
- class FreeResponse extends React__namespace.Component{isOverLimit(){return !this.props.allowUnlimitedCharacters&&this.characterCount()>this.props.characterLimit}render(){const isOverLimit=this.isOverLimit();const characterCountText=this.props.allowUnlimitedCharacters?undefined:this.context.strings.characterCount({used:this.characterCount(),num:this.props.characterLimit});if(characterCountText){this.announceCharacterCount(characterCountText,isOverLimit);}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$l.container,className:"free-response",children:jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:"free-response-question",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.question,strings:this.context.strings})}),field:jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{error:isOverLimit,onChange:this._handleUserInput,placeholder:this.props.placeholder,style:styles$l.textarea,value:this.props.userInput.currentValue}),additionalHelperMessage:jsxRuntimeExports.jsxs("p",{className:aphrodite.css(styles$l.characterCountText,isOverLimit?styles$l.overCharacterLimit:undefined),children:[isOverLimit&&jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{"aria-label":"Error:",icon:warningCircleIcon__default.default,size:"small",style:styles$l.warningCircleIcon}),characterCountText]})})})}constructor(...args){super(...args),this.isWidget=true,this.announceCharacterCount=(message,isOverLimit)=>{const level=isOverLimit?"assertive":"polite";wonderBlocksAnnouncer.announceMessage({message,level,debounceThreshold:750});},this.characterCount=()=>{return this.props.userInput.currentValue.replace(/\n/g,"").length},this._handleUserInput=newValue=>{this.props.handleUserInput({currentValue:newValue});};}}FreeResponse.contextType=PerseusI18nContext;FreeResponse.defaultProps={userInput:{currentValue:""}};function getStartUserInput$c(){return {currentValue:""}}var FreeResponse$1 = {name:"free-response",accessible:true,displayName:"Free Response (Assessments only)",widget:FreeResponse,hidden:false,getUserInputFromSerializedState:getStartUserInput$c,getStartUserInput: getStartUserInput$c};const styles$l=aphrodite.StyleSheet.create({container:{gap:wonderBlocksTokens.spacing.xSmall_8},characterCountText:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,fontSize:wonderBlocksTokens.font.body.size.small,margin:0},overCharacterLimit:{color:wonderBlocksTokens.semanticColor.core.foreground.critical.default},textarea:{padding:wonderBlocksTokens.spacing.medium_16},warningCircleIcon:{marginInlineEnd:wonderBlocksTokens.spacing.xSmall_8}});
1824
+ class FreeResponse extends React__namespace.Component{isOverLimit(){return !this.props.allowUnlimitedCharacters&&this.characterCount()>this.props.characterLimit}render(){const isOverLimit=this.isOverLimit();const characterCountText=this.props.allowUnlimitedCharacters?undefined:this.context.strings.characterCount({used:this.characterCount(),num:this.props.characterLimit});if(characterCountText){this.announceCharacterCount(characterCountText,isOverLimit);}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$m.container,className:"free-response",children:jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:"free-response-question",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.question,strings:this.context.strings})}),field:jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{error:isOverLimit,onChange:this._handleUserInput,placeholder:this.props.placeholder,style:styles$m.textarea,value:this.props.userInput.currentValue}),additionalHelperMessage:jsxRuntimeExports.jsxs("p",{className:aphrodite.css(styles$m.characterCountText,isOverLimit?styles$m.overCharacterLimit:undefined),children:[isOverLimit&&jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{"aria-label":"Error:",icon:warningCircleIcon__default.default,size:"small",style:styles$m.warningCircleIcon}),characterCountText]})})})}constructor(...args){super(...args),this.isWidget=true,this.announceCharacterCount=(message,isOverLimit)=>{const level=isOverLimit?"assertive":"polite";wonderBlocksAnnouncer.announceMessage({message,level,debounceThreshold:750});},this.characterCount=()=>{return this.props.userInput.currentValue.replace(/\n/g,"").length},this._handleUserInput=newValue=>{this.props.handleUserInput({currentValue:newValue});};}}FreeResponse.contextType=PerseusI18nContext;FreeResponse.defaultProps={userInput:{currentValue:""}};function getStartUserInput$c(){return {currentValue:""}}var FreeResponse$1 = {name:"free-response",accessible:true,displayName:"Free Response (Assessments only)",widget:FreeResponse,hidden:false,getUserInputFromSerializedState:getStartUserInput$c,getStartUserInput: getStartUserInput$c};const styles$m=aphrodite.StyleSheet.create({container:{gap:wonderBlocksTokens.spacing.xSmall_8},characterCountText:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,fontSize:wonderBlocksTokens.font.body.size.small,margin:0},overCharacterLimit:{color:wonderBlocksTokens.semanticColor.core.foreground.critical.default},textarea:{padding:wonderBlocksTokens.spacing.medium_16},warningCircleIcon:{marginInlineEnd:wonderBlocksTokens.spacing.xSmall_8}});
1825
1825
 
1826
1826
  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}};
1827
1827
 
1828
- class GradedGroupAnswerBar extends React__namespace.Component{render(){const{apiOptions,answerBarState,onCheckAnswer,onNextQuestion}=this.props;const{keepTrying,tryAgain,check,correctExcited,nextQuestion}=this.context.strings;const answerBarStyle={...styles$k.answerBar,backgroundColor:answerBarState==="CORRECT"?wonderBlocksTokens.semanticColor.core.background.base.subtle:wonderBlocksTokens.semanticColor.core.background.base.default,justifyContent:answerBarState==="CORRECT"&&!onNextQuestion?"center":"space-between"};const message=answerBarState==="INCORRECT"?jsxRuntimeExports.jsxs("span",{style:styles$k.text,children:[jsxRuntimeExports.jsx("span",{style:styles$k.tryAgainIcon,children:jsxRuntimeExports.jsx(InlineIcon,{...iconTryAgain})}),jsxRuntimeExports.jsx("span",{style:{marginLeft:8},children:keepTrying})]}):jsxRuntimeExports.jsx("span",{});if(answerBarState!=="CORRECT"){const buttonLabel=answerBarState==="INCORRECT"?tryAgain:check;return jsxRuntimeExports.jsxs("div",{style:answerBarStyle,children:[message,jsxRuntimeExports.jsx(Button__default.default,{disabled:apiOptions.readOnly||answerBarState!=="ACTIVE",onClick:onCheckAnswer,children:buttonLabel})]})}return jsxRuntimeExports.jsxs("div",{style:answerBarStyle,children:[jsxRuntimeExports.jsxs("span",{style:styles$k.text,children:[jsxRuntimeExports.jsx("span",{style:{fontSize:28,color:wonderBlocksTokens.semanticColor.core.foreground.success.default},children:jsxRuntimeExports.jsx(InlineIcon,{...iconStar,style:{marginBottom:5}})}),jsxRuntimeExports.jsx("span",{role:"alert","aria-label":correctExcited,style:{marginLeft:8},children:correctExcited})]}),onNextQuestion&&jsxRuntimeExports.jsx(Button__default.default,{onClick:onNextQuestion,children:nextQuestion})]})}}GradedGroupAnswerBar.contextType=PerseusI18nContext;const fontSize$1=17;const styles$k={answerBar:{display:"flex",alignItems:"center",height:68,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,marginBottom:negativePhoneMargin,marginTop:phoneMargin,paddingLeft:phoneMargin,paddingRight:10,borderTop:`1px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`},tryAgainIcon:{fontSize:28,color:"#63D9EA",transform:"scale(-1,1) rotate(-268deg)"},text:{display:"flex",flexDirection:"row",alignItems:"center",fontWeight:"bold",fontSize:fontSize$1}};
1828
+ class GradedGroupAnswerBar extends React__namespace.Component{render(){const{apiOptions,answerBarState,onCheckAnswer,onNextQuestion}=this.props;const{keepTrying,tryAgain,check,correctExcited,nextQuestion}=this.context.strings;const answerBarStyle={...styles$l.answerBar,backgroundColor:answerBarState==="CORRECT"?wonderBlocksTokens.semanticColor.core.background.base.subtle:wonderBlocksTokens.semanticColor.core.background.base.default,justifyContent:answerBarState==="CORRECT"&&!onNextQuestion?"center":"space-between"};const message=answerBarState==="INCORRECT"?jsxRuntimeExports.jsxs("span",{style:styles$l.text,children:[jsxRuntimeExports.jsx("span",{style:styles$l.tryAgainIcon,children:jsxRuntimeExports.jsx(InlineIcon,{...iconTryAgain})}),jsxRuntimeExports.jsx("span",{style:{marginLeft:8},children:keepTrying})]}):jsxRuntimeExports.jsx("span",{});if(answerBarState!=="CORRECT"){const buttonLabel=answerBarState==="INCORRECT"?tryAgain:check;return jsxRuntimeExports.jsxs("div",{style:answerBarStyle,children:[message,jsxRuntimeExports.jsx(Button__default.default,{disabled:apiOptions.readOnly||answerBarState!=="ACTIVE",onClick:onCheckAnswer,children:buttonLabel})]})}return jsxRuntimeExports.jsxs("div",{style:answerBarStyle,children:[jsxRuntimeExports.jsxs("span",{style:styles$l.text,children:[jsxRuntimeExports.jsx("span",{style:{fontSize:28,color:wonderBlocksTokens.semanticColor.core.foreground.success.default},children:jsxRuntimeExports.jsx(InlineIcon,{...iconStar,style:{marginBottom:5}})}),jsxRuntimeExports.jsx("span",{role:"alert","aria-label":correctExcited,style:{marginLeft:8},children:correctExcited})]}),onNextQuestion&&jsxRuntimeExports.jsx(Button__default.default,{onClick:onNextQuestion,children:nextQuestion})]})}}GradedGroupAnswerBar.contextType=PerseusI18nContext;const fontSize$1=17;const styles$l={answerBar:{display:"flex",alignItems:"center",height:68,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,marginBottom:negativePhoneMargin,marginTop:phoneMargin,paddingLeft:phoneMargin,paddingRight:10,borderTop:`1px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`},tryAgainIcon:{fontSize:28,color:"#63D9EA",transform:"scale(-1,1) rotate(-268deg)"},text:{display:"flex",flexDirection:"row",alignItems:"center",fontWeight:"bold",fontSize:fontSize$1}};
1829
1829
 
1830
- const GRADING_STATUSES={ungraded:"ungraded",correct:"correct",incorrect:"incorrect",invalid:"invalid"};const getNextState=(currentState,answerable)=>{switch(currentState){case "ACTIVE":return !answerable?"INACTIVE":currentState;case "INACTIVE":return answerable?"ACTIVE":currentState;case "INCORRECT":return answerable?"ACTIVE":"INACTIVE";default:return currentState}};class GradedGroup extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"graded-group",widgetSubType:"null",widgetId:this.props.widgetId}});}shouldComponentUpdate(nextProps,nextState){return nextProps!==this.props||nextState!==this.state}_handleUserInput(_userInput,widgetsEmpty){this.setState({status:GRADING_STATUSES.ungraded,message:""});const answerable=!widgetsEmpty;const answerBarState=this.state.answerBarState;const nextState=getNextState(answerBarState,answerable);this.setState({answerBarState:nextState});}getPromptJSON(){const hint=this.hintRendererRef.current?.getPromptJSON()||{content:this.props.hint?.content||"",widgets:{}};return getPromptJSON$i(this.props.title,this.rendererRef.current?.getPromptJSON(),hint)}render(){const apiOptions=___default.default.extend({},ApiOptions.defaults,this.props.apiOptions,{onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}});let gradeStatus=null;let icon=null;if(this.state.status===GRADING_STATUSES.correct){icon=jsxRuntimeExports.jsx(InlineIcon,{...iconOk,style:{color:"#526f03"}});gradeStatus=this.context.strings.correct;}else if(this.state.status===GRADING_STATUSES.incorrect){icon=jsxRuntimeExports.jsx(InlineIcon,{...iconRemove,style:{color:"#ff5454"}});gradeStatus=this.context.strings.incorrect;}const mobileClass=this.props.inGradedGroupSet?aphrodite.css(styles$j.gradedGroupInSet):aphrodite.css(styles$j.gradedGroup);const classes=classNames__default.default({[mobileClass]:apiOptions.isMobile,"perseus-graded-group":true,"answer-correct":apiOptions.isMobile?false:this.state.status===GRADING_STATUSES.correct,"answer-incorrect":apiOptions.isMobile?false:this.state.status===GRADING_STATUSES.incorrect});const{answerBarState}=this.state;const isCorrect=answerBarState==="CORRECT";const readOnly=apiOptions.readOnly||apiOptions.isMobile&&isCorrect;const showSolutions=isCorrect?"all":"none";return jsxRuntimeExports.jsxs("div",{className:classes,children:[!!this.props.title&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$j.title),children:this.props.title}),jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.widgets,handleUserInput:(userInput,widgetsEmpty)=>this._handleUserInput(userInput,widgetsEmpty),problemNum:0,children:({userInput,handleUserInput})=>jsxRuntimeExports.jsx(Renderer,{content:this.props.content,widgets:this.props.widgets,images:this.props.images,userInput:userInput,handleUserInput:handleUserInput,problemNum:0,ref:this.rendererRef,keypadElement:this.props.keypadElement,apiOptions:{...apiOptions,readOnly},showSolutions:showSolutions,linterContext:this.props.linterContext,strings:this.context.strings})}),!apiOptions.isMobile&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[icon!=null&&jsxRuntimeExports.jsx("div",{className:"group-icon",children:icon}),gradeStatus&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(a11y.srOnly),role:"alert","aria-label":gradeStatus,children:gradeStatus}),jsxRuntimeExports.jsx("div",{role:"status","aria-live":"polite",children:jsxRuntimeExports.jsx(Renderer,{content:this.state.message,strings:this.context.strings})}),jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:this.props.apiOptions.readOnly,onClick:this._checkAnswer,children:this.context.strings.check}),isCorrect&&this.props.onNextQuestion&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:this.props.apiOptions.readOnly,onClick:this.props.onNextQuestion,style:{marginLeft:5},children:this.context.strings.nextQuestion})]}),this.props.hint?.content&&(this.state.showHint?jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("button",{tabIndex:"0",className:aphrodite.css(styles$j.explanationTitle),onClick:()=>this.setState({showHint:false}),onKeyPress:e=>{e.preventDefault();this.setState({showHint:false});},children:this.context.strings.hideExplanation}),jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.hint.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>{const{content,widgets,images}=this.props.hint;return jsxRuntimeExports.jsx(Renderer,{content:content,widgets:widgets,images:images,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,ref:this.hintRendererRef,apiOptions:apiOptions,linterContext:this.props.linterContext,strings:this.context.strings,showSolutions:showSolutions})}})]}):jsxRuntimeExports.jsx("button",{tabIndex:"0",onClick:()=>this.setState({showHint:true}),onKeyPress:e=>{e.preventDefault();this.setState({showHint:true});},className:aphrodite.css(styles$j.showHintLink),children:this.context.strings.explain})),apiOptions.isMobile&&jsxRuntimeExports.jsx(GradedGroupAnswerBar,{apiOptions:apiOptions,answerBarState:answerBarState,onCheckAnswer:this._checkAnswer,onNextQuestion:this.props.onNextQuestion})]})}constructor(...args){super(...args),this.state={status:GRADING_STATUSES.ungraded,showHint:false,message:"",answerBarState:"INACTIVE"},this.rendererRef=React__namespace.createRef(),this.hintRendererRef=React__namespace.createRef(),this._checkAnswer=()=>{const score=this.rendererRef.current?.score()||{type:"invalid"};const{INVALID_MESSAGE_PREFIX,DEFAULT_INVALID_MESSAGE_1,DEFAULT_INVALID_MESSAGE_2}=this.context.strings;const status=score.type==="points"?score.total===score.earned?GRADING_STATUSES.correct:GRADING_STATUSES.incorrect:GRADING_STATUSES.invalid;const message=score.type==="points"?score.message||"":score.message?`${INVALID_MESSAGE_PREFIX} ${mapErrorToString(score.message,this.context.strings)}`:`${INVALID_MESSAGE_PREFIX} ${DEFAULT_INVALID_MESSAGE_1}${DEFAULT_INVALID_MESSAGE_2}`;this.setState({status:status,message:message,answerBarState:status==="correct"?"CORRECT":"INCORRECT"});this.props.trackInteraction({status:status});},this.getInputPaths=()=>{return this.rendererRef.current?.getInputPaths()||[]},this.focus=()=>{return !!this.rendererRef.current?.focus()},this.focusInputPath=path=>{this.rendererRef.current?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef.current?.blurPath(path);};}}GradedGroup.contextType=PerseusI18nContext;GradedGroup.defaultProps={title:"",content:"",widgets:{},images:{},hint:null,hasHint:false,linterContext:PerseusLinter.linterContextDefault};const styles$j=aphrodite.StyleSheet.create({gradedGroupInSet:{marginLeft:0,paddingLeft:0},gradedGroup:{borderTop:`1px solid ${gray76}`,borderBottom:`1px solid ${gray76}`,backgroundColor:tableBackgroundAccent,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,paddingBottom:phoneMargin,paddingLeft:phoneMargin,paddingRight:phoneMargin,paddingTop:10,width:"auto"},showHintLink:{backgroundColor:"unset",fontSize:14,padding:0,border:"none",marginTop:20,color:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,cursor:"pointer",display:"block",clear:"both"},explanationTitle:{backgroundColor:"unset",marginTop:20,color:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,marginBottom:10,cursor:"pointer",fontSize:14,padding:0,border:"none",display:"block",clear:"both"},title:{fontSize:12,color:gray68,textTransform:"uppercase",marginBottom:11,letterSpacing:.8}});const WrappedGradedGroup=withDependencies(GradedGroup);var GradedGroup$1 = {name:"graded-group",displayName:"Graded group (articles only)",widget:WrappedGradedGroup,hidden:false,tracking:"all",isLintable:true};
1830
+ const GRADING_STATUSES={ungraded:"ungraded",correct:"correct",incorrect:"incorrect",invalid:"invalid"};const getNextState=(currentState,answerable)=>{switch(currentState){case "ACTIVE":return !answerable?"INACTIVE":currentState;case "INACTIVE":return answerable?"ACTIVE":currentState;case "INCORRECT":return answerable?"ACTIVE":"INACTIVE";default:return currentState}};class GradedGroup extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"graded-group",widgetSubType:"null",widgetId:this.props.widgetId}});}shouldComponentUpdate(nextProps,nextState){return nextProps!==this.props||nextState!==this.state}_handleUserInput(_userInput,widgetsEmpty){this.setState({status:GRADING_STATUSES.ungraded,message:""});const answerable=!widgetsEmpty;const answerBarState=this.state.answerBarState;const nextState=getNextState(answerBarState,answerable);this.setState({answerBarState:nextState});}getPromptJSON(){const hint=this.hintRendererRef.current?.getPromptJSON()||{content:this.props.hint?.content||"",widgets:{}};return getPromptJSON$i(this.props.title,this.rendererRef.current?.getPromptJSON(),hint)}render(){const apiOptions=___default.default.extend({},ApiOptions.defaults,this.props.apiOptions,{onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}});let gradeStatus=null;let icon=null;if(this.state.status===GRADING_STATUSES.correct){icon=jsxRuntimeExports.jsx(InlineIcon,{...iconOk,style:{color:"#526f03"}});gradeStatus=this.context.strings.correct;}else if(this.state.status===GRADING_STATUSES.incorrect){icon=jsxRuntimeExports.jsx(InlineIcon,{...iconRemove,style:{color:"#ff5454"}});gradeStatus=this.context.strings.incorrect;}const mobileClass=this.props.inGradedGroupSet?aphrodite.css(styles$k.gradedGroupInSet):aphrodite.css(styles$k.gradedGroup);const classes=classNames__default.default({[mobileClass]:apiOptions.isMobile,"perseus-graded-group":true,"answer-correct":apiOptions.isMobile?false:this.state.status===GRADING_STATUSES.correct,"answer-incorrect":apiOptions.isMobile?false:this.state.status===GRADING_STATUSES.incorrect});const{answerBarState}=this.state;const isCorrect=answerBarState==="CORRECT";const readOnly=apiOptions.readOnly||apiOptions.isMobile&&isCorrect;const showSolutions=isCorrect?"all":"none";return jsxRuntimeExports.jsxs("div",{className:classes,children:[!!this.props.title&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$k.title),children:this.props.title}),jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.widgets,handleUserInput:(userInput,widgetsEmpty)=>this._handleUserInput(userInput,widgetsEmpty),problemNum:0,children:({userInput,handleUserInput})=>jsxRuntimeExports.jsx(Renderer,{content:this.props.content,widgets:this.props.widgets,images:this.props.images,userInput:userInput,handleUserInput:handleUserInput,problemNum:0,ref:this.rendererRef,keypadElement:this.props.keypadElement,apiOptions:{...apiOptions,readOnly},showSolutions:showSolutions,linterContext:this.props.linterContext,strings:this.context.strings})}),!apiOptions.isMobile&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[icon!=null&&jsxRuntimeExports.jsx("div",{className:"group-icon",children:icon}),gradeStatus&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(a11y.srOnly),role:"alert","aria-label":gradeStatus,children:gradeStatus}),jsxRuntimeExports.jsx("div",{role:"status","aria-live":"polite",children:jsxRuntimeExports.jsx(Renderer,{content:this.state.message,strings:this.context.strings})}),jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:this.props.apiOptions.readOnly,onClick:this._checkAnswer,children:this.context.strings.check}),isCorrect&&this.props.onNextQuestion&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:this.props.apiOptions.readOnly,onClick:this.props.onNextQuestion,style:{marginLeft:5},children:this.context.strings.nextQuestion})]}),this.props.hint?.content&&(this.state.showHint?jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("button",{tabIndex:"0",className:aphrodite.css(styles$k.explanationTitle),onClick:()=>this.setState({showHint:false}),onKeyPress:e=>{e.preventDefault();this.setState({showHint:false});},children:this.context.strings.hideExplanation}),jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.hint.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>{const{content,widgets,images}=this.props.hint;return jsxRuntimeExports.jsx(Renderer,{content:content,widgets:widgets,images:images,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,ref:this.hintRendererRef,apiOptions:apiOptions,linterContext:this.props.linterContext,strings:this.context.strings,showSolutions:showSolutions})}})]}):jsxRuntimeExports.jsx("button",{tabIndex:"0",onClick:()=>this.setState({showHint:true}),onKeyPress:e=>{e.preventDefault();this.setState({showHint:true});},className:aphrodite.css(styles$k.showHintLink),children:this.context.strings.explain})),apiOptions.isMobile&&jsxRuntimeExports.jsx(GradedGroupAnswerBar,{apiOptions:apiOptions,answerBarState:answerBarState,onCheckAnswer:this._checkAnswer,onNextQuestion:this.props.onNextQuestion})]})}constructor(...args){super(...args),this.state={status:GRADING_STATUSES.ungraded,showHint:false,message:"",answerBarState:"INACTIVE"},this.rendererRef=React__namespace.createRef(),this.hintRendererRef=React__namespace.createRef(),this._checkAnswer=()=>{const score=this.rendererRef.current?.score()||{type:"invalid"};const{INVALID_MESSAGE_PREFIX,DEFAULT_INVALID_MESSAGE_1,DEFAULT_INVALID_MESSAGE_2}=this.context.strings;const status=score.type==="points"?score.total===score.earned?GRADING_STATUSES.correct:GRADING_STATUSES.incorrect:GRADING_STATUSES.invalid;const message=score.type==="points"?score.message||"":score.message?`${INVALID_MESSAGE_PREFIX} ${mapErrorToString(score.message,this.context.strings)}`:`${INVALID_MESSAGE_PREFIX} ${DEFAULT_INVALID_MESSAGE_1}${DEFAULT_INVALID_MESSAGE_2}`;this.setState({status:status,message:message,answerBarState:status==="correct"?"CORRECT":"INCORRECT"});this.props.trackInteraction({status:status});},this.getInputPaths=()=>{return this.rendererRef.current?.getInputPaths()||[]},this.focus=()=>{return !!this.rendererRef.current?.focus()},this.focusInputPath=path=>{this.rendererRef.current?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef.current?.blurPath(path);};}}GradedGroup.contextType=PerseusI18nContext;GradedGroup.defaultProps={title:"",content:"",widgets:{},images:{},hint:null,hasHint:false,linterContext:PerseusLinter.linterContextDefault};const styles$k=aphrodite.StyleSheet.create({gradedGroupInSet:{marginLeft:0,paddingLeft:0},gradedGroup:{borderTop:`1px solid ${gray76}`,borderBottom:`1px solid ${gray76}`,backgroundColor:tableBackgroundAccent,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,paddingBottom:phoneMargin,paddingLeft:phoneMargin,paddingRight:phoneMargin,paddingTop:10,width:"auto"},showHintLink:{backgroundColor:"unset",fontSize:14,padding:0,border:"none",marginTop:20,color:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,cursor:"pointer",display:"block",clear:"both"},explanationTitle:{backgroundColor:"unset",marginTop:20,color:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,marginBottom:10,cursor:"pointer",fontSize:14,padding:0,border:"none",display:"block",clear:"both"},title:{fontSize:12,color:gray68,textTransform:"uppercase",marginBottom:11,letterSpacing:.8}});const WrappedGradedGroup=withDependencies(GradedGroup);var GradedGroup$1 = {name:"graded-group",displayName:"Graded group (articles only)",widget:WrappedGradedGroup,hidden:false,tracking:"all",isLintable:true};
1831
1831
 
1832
1832
  const getPromptJSON$h=(widgetData,activeGroupJSON)=>{return {type:"graded-group-set",options:{groupCount:widgetData.gradedGroups.length,currentGroup:activeGroupJSON}}};
1833
1833
 
1834
- class Indicators extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("ul",{role:"list",className:classNames__default.default(aphrodite.css(styles$i.indicatorContainer),"indicatorContainer"),children:this.props.gradedGroups.map(({title},i)=>jsxRuntimeExports.jsx("li",{className:aphrodite.css(styles$i.indicator),children:jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-label":title,"aria-current":i===this.props.currentGroup,style:styles$i.indicatorButton,onClick:()=>this.props.onChangeCurrentGroup(i),onKeyDown:e=>this.handleKeyDown(e,i),children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$i.indicatorDot,(hovered||focused||pressed)&&styles$i.indicatorDotFocused],children:i===this.props.currentGroup&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$i.indicatorDotActive})})})},i))})}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{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"graded-group-set",widgetSubType:"null",widgetId:this.props.widgetId}});}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$i.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$i.container),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$i.top),children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$i.title),children:currentGroup.title}),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$i.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};const WrappedGradedGroupSet=withDependencies(GradedGroupSet);var GradedGroupSet$1 = {name:"graded-group-set",displayName:"Graded group set (articles only)",widget:WrappedGradedGroupSet,hidden:false,tracking:"all",isLintable:true};const styles$i=aphrodite.StyleSheet.create({top:{display:"flex",flexDirection:"row"},spacer:{flex:1},title:{fontSize:12,color:wonderBlocksTokens.semanticColor.core.foreground.neutral.subtle,textTransform:"uppercase",marginBottom:11,letterSpacing:.8},indicatorContainer:{display:"flex",flexDirection:"row",listStyleType:"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.semanticColor.core.border.instructive.default,borderStyle:"solid"},indicatorDotFocused:{borderWidth:5,borderStyle:"double"},indicatorDotActive:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default,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"}});
1834
+ class Indicators extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("ul",{role:"list",className:classNames__default.default(aphrodite.css(styles$j.indicatorContainer),"indicatorContainer"),children:this.props.gradedGroups.map(({title},i)=>jsxRuntimeExports.jsx("li",{className:aphrodite.css(styles$j.indicator),children:jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-label":title,"aria-current":i===this.props.currentGroup,style:styles$j.indicatorButton,onClick:()=>this.props.onChangeCurrentGroup(i),onKeyDown:e=>this.handleKeyDown(e,i),children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$j.indicatorDot,(hovered||focused||pressed)&&styles$j.indicatorDotFocused],children:i===this.props.currentGroup&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$j.indicatorDotActive})})})},i))})}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{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"graded-group-set",widgetSubType:"null",widgetId:this.props.widgetId}});}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$j.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$j.container),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$j.top),children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$j.title),children:currentGroup.title}),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$j.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};const WrappedGradedGroupSet=withDependencies(GradedGroupSet);var GradedGroupSet$1 = {name:"graded-group-set",displayName:"Graded group set (articles only)",widget:WrappedGradedGroupSet,hidden:false,tracking:"all",isLintable:true};const styles$j=aphrodite.StyleSheet.create({top:{display:"flex",flexDirection:"row"},spacer:{flex:1},title:{fontSize:12,color:wonderBlocksTokens.semanticColor.core.foreground.neutral.subtle,textTransform:"uppercase",marginBottom:11,letterSpacing:.8},indicatorContainer:{display:"flex",flexDirection:"row",listStyleType:"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.semanticColor.core.border.instructive.default,borderStyle:"solid"},indicatorDotFocused:{borderWidth:5,borderStyle:"double"},indicatorDotActive:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default,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"}});
1835
1835
 
1836
- 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$h.buttonStyle,button.value===value&&styles$h.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$h=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"}});
1836
+ 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$i.buttonStyle,button.value===value&&styles$i.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$i=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"}});
1837
1837
 
1838
1838
  const getPromptJSON$g=widgetData=>{const{userInput}=widgetData;const{type,coords}=userInput;const input={type,coords};if(userInput.type==="logarithm"||userInput.type==="exponential"){input["asymptote"]=userInput.asymptote;}return {type:"grapher",options:{availableTypes:widgetData.availableTypes,range:widgetData.graph.range,labels:widgetData.graph.labels,tickStep:widgetData.graph.step,gridStep:widgetData.graph.gridStep,snapStep:widgetData.graph.snapStep,backgroundImageUrl:widgetData.graph.backgroundImage.url},userInput:input}};
1839
1839
 
1840
1840
  const movableTypeToComponent={PLOT:Graphie.Plot,PARABOLA:Graphie.Parabola,SINUSOID:Graphie.Sinusoid};const DEFAULT_BACKGROUND_IMAGE={url:null};const getEquationString$1=plot=>{if(plot.type&&plot.coords){const handler=perseusCore.GrapherUtil.functionForType(plot.type);const result=handler.getEquationString(plot.coords,plot.asymptote);return result||""}return ""};const pointsFromNormalized$1=(coordsList,range,step,snapStep)=>{const numSteps=function(range,step){return Math.floor((range[1]-range[0])/step)};return coordsList.map(coords=>{const unsnappedPoint=coords.map((coord,i)=>{const currRange=range[i];const currStep=step[i];const nSteps=numSteps(currRange,currStep);const tick=Math.round(coord*nSteps);return currRange[0]+currStep*tick});return kmath.point.roundTo(unsnappedPoint,snapStep)})};const maybePointsFromNormalized=(coordsList,range,step,snapStep)=>{if(coordsList){return pointsFromNormalized$1(coordsList,range,step,snapStep)}return coordsList};const defaultPlotProps=(type,graph)=>{const model=perseusCore.GrapherUtil.functionForType(type);const defaultAsymptote="defaultAsymptote"in model?model.defaultAsymptote:null;const gridStep=[1,1];const snapStep=Util.snapStepFromGridStep(gridStep);return {type,asymptote:maybePointsFromNormalized(defaultAsymptote,graph.range,graph.step,snapStep),coords:null}};const chooseType=___default.default.first;const getGridAndSnapSteps=(options,boxSize)=>{const gridStep=options.gridStep||Util.getGridStep(options.range,options.step,boxSize);const snapStep=options.snapStep||Util.snapStepFromGridStep(gridStep);return {gridStep:gridStep,snapStep:snapStep}};const defaultGraph={labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],backgroundImage:DEFAULT_BACKGROUND_IMAGE,markings:"graph",rulerLabel:"",rulerTicks:10,valid:true,showTooltips:false};const defaultPlot=defaultPlotProps("linear",defaultGraph);const DEFAULT_GRAPHER_PROPS={graph:defaultGraph,plot:defaultPlot,availableTypes:[defaultPlot.type]};const typeToButton=type=>{const capitalized=type.charAt(0).toUpperCase()+type.substring(1);const staticUrl=getDependencies().staticUrl;return {value:type,title:capitalized,content:jsxRuntimeExports.jsx("img",{src:staticUrl(perseusCore.GrapherUtil.functionForType(type).url),alt:capitalized})}};
1841
1841
 
1842
- const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLine;function isFlipped(newCoord,oldCoord,line){const CCW=(a,b,c)=>{return (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])};return CCW(line[0],line[1],oldCoord)>0!==CCW(line[0],line[1],newCoord)>0}const typeSelectorStyle={padding:"5px 5px"};class FunctionGrapher extends React__namespace.Component{render(){const pointForCoord=(coord,i)=>{return jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:this.props.static,constraints:[Interactive2.MovablePoint.constraints.bound(),Interactive2.MovablePoint.constraints.snap(),coord=>{const isFunction=this._coords().every((otherCoord,j)=>{return i===j||!otherCoord||!kmath.number.equal(coord[0],otherCoord[0])});if(!isFunction){return false}if(this.props.model&&this.props.model.extraCoordConstraint){const extraConstraint=this.props.model.extraCoordConstraint;const proposedCoords=perseusCore.deepClone(this._coords());const oldCoord=perseusCore.deepClone(proposedCoords[i]);proposedCoords[i]=coord;return extraConstraint(coord,oldCoord,proposedCoords,this._asymptote(),this.props.graph)}return isFunction}],onMove:(newCoord,oldCoord)=>{let coords;const asymptote=this._asymptote();if(asymptote&&this.props.model.allowReflectOverAsymptote&&isFlipped(newCoord,oldCoord,asymptote)){coords=this._coords().map(coord=>{return kmath.point.reflectOverLine(coord,asymptote)});}else {coords=perseusCore.deepClone(this._coords());}coords[i]=newCoord;this.props.onChange({coords:coords});},showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},i)};const points=this._coords().map(pointForCoord);const box=this.props.graph.box;const imageDescription=this.props.graph.backgroundImage;let image=null;if(imageDescription.url){const scale=box[0]/interactiveSizes$1.defaultBoxSize;image=jsxRuntimeExports.jsx(SvgImage,{src:imageDescription.url,allowZoom:false,width:imageDescription.width,height:imageDescription.height,scale:scale});}return jsxRuntimeExports.jsx("div",{className:"perseus-widget "+"perseus-widget-grapher",style:{width:box[0],height:box[1],boxSizing:"initial"},children:jsxRuntimeExports.jsxs("div",{className:"graphie-container blank-background",style:{width:box[0],height:box[1]},children:[image,jsxRuntimeExports.jsxs(Graphie,{...this.props.graph,setDrawingAreaAvailable:this.props.setDrawingAreaAvailable,children:[this.props.model&&this.renderPlot(),this.props.model&&this.renderAsymptote(),this.props.model&&points]})]})})}constructor(...args){super(...args),this._coords=()=>{const props=this.props;const graph=props.graph;const defaultModelCoords=props.model&&maybePointsFromNormalized(props.model.defaultCoords,graph.range,graph.step,graph.snapStep);return props.coords||defaultModelCoords||null},this._asymptote=()=>{return this.props.asymptote},this.renderPlot=()=>{const model=this.props.model;const xRange=this.props.graph.range[0];const style={stroke:this.props.isMobile?KhanColors.BLUE_C:KhanColors.DYNAMIC,...this.props.isMobile?{"stroke-width":3}:{}};const coeffs=model.getCoefficients(this._coords(),this._asymptote());if(!coeffs){return}const functionProps=model.getPropsForCoeffs(coeffs,xRange);const Movable=movableTypeToComponent[model.movable];return React.createElement(Movable,{...functionProps,key:this.props.model.url,range:xRange,style:style})},this.renderAsymptote=()=>{const model=this.props.model;const graph=this.props.graph;const asymptote=this._asymptote();const showAsymptote=asymptote?.length>0;const dashed={strokeDasharray:"- "};return showAsymptote&&jsxRuntimeExports.jsx(MovableLine$2,{onMove:(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const newAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const proposedAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:asymptote.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:true,draw:null,extendLine:true,showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},`asymptoteCoord-${i}`))})};}}FunctionGrapher.defaultProps={graph:{range:[[-10,10],[-10,10]],step:[1,1]},coords:null,asymptote:null,isMobile:false};class Grapher extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"grapher",widgetSubType:"null",widgetId:this.props.widgetId}});}_getGridConfig(options){return options.step.map((step,i)=>{return Util.gridDimensionConfig(step,options.range[i],options.box[i],options.gridStep[i])})}_calculateMobileTickStep(gridStep,step,ranges){const tickStep=Util.constrainedTickStepsFromTickSteps(step,ranges);tickStep[0]=tickStep[0]/gridStep[0];tickStep[1]=tickStep[1]/gridStep[1];return tickStep}getPromptJSON(){return getPromptJSON$g(this.props)}getSerializedState(){const{userInput:_,correct:__,...rest}=this.props;return {...rest,plot:this.props.userInput}}render(){const availableTypes=this.props.static?[this.props.correct.type]:this.props.availableTypes;const type=this.props.userInput.type;const coords=this.props.userInput.coords;const asymptote="asymptote"in this.props.userInput?this.props.userInput.asymptote:undefined;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:availableTypes.map(typeToButton),onChange:this.handleActiveTypeChange})});const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const options={...this.props.graph,...getGridAndSnapSteps(this.props.graph,box[0]),gridConfig:this._getGridConfig({...this.props.graph,box:box,...getGridAndSnapSteps(this.props.graph,box[0])})};const grapherProps={graph:{box:box,range:options.range,step:options.step,snapStep:options.snapStep,backgroundImage:options.backgroundImage,options:options,setup:this._setupGraphie},onChange:this.handlePlotChanges,model:type&&perseusCore.GrapherUtil.functionForType(type),coords:coords,asymptote:asymptote,static:this.props.static,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,showTooltips:this.props.graph.showTooltips,showHairlines:this.showHairlines,hideHairlines:this.hideHairlines};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(FunctionGrapher,{...grapherProps}),availableTypes.length>1&&typeSelector]})}constructor(...args){super(...args),this.handlePlotChanges=newPlot=>{const plot={...this.props.userInput,...newPlot};this.props.handleUserInput(plot);this.props.trackInteraction();},this.handleActiveTypeChange=newType=>{const graph=this.props.graph;const plot={...this.props.userInput,...defaultPlotProps(newType,graph)};this.props.handleUserInput(plot);},this._setupGraphie=(graphie,options)=>{const isMobile=this.props.apiOptions.isMobile;if(options.markings==="graph"){graphie.graphInit({range:options.range,scale:options.gridConfig.map(e=>e.scale),axisArrows:"<->",labelFormat:function(s){return "\\small{"+s+"}"},gridStep:options.gridStep,snapStep:options.snapStep,tickStep:isMobile?this._calculateMobileTickStep(options.gridStep,options.step,options.range):options.gridConfig.map(e=>e.tickStep),labelStep:1,unityLabels:options.gridConfig.map(e=>e.unityLabel),isMobile:isMobile});graphie.label([0,options.range[1][1]],options.labels[1],isMobile?"below right":"above");graphie.label([options.range[0][1],0],options.labels[0],isMobile?"above left":"right");}else if(options.markings==="grid"){graphie.graphInit({range:options.range,scale:options.gridConfig.map(e=>e.scale),gridStep:options.gridStep,axes:false,ticks:false,labels:false,isMobile:isMobile});}else if(options.markings==="none"){graphie.init({range:options.range,scale:options.gridConfig.map(e=>e.scale)});}if(this.props.apiOptions.isMobile){const hairlineStyle={normalStyle:{strokeWidth:1}};this.horizHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.vertHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.vertHairline.attr({stroke:KhanColors.INTERACTIVE});this.vertHairline.hide();}},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.props.graph.range[0][0],point[1]],[this.props.graph.range[0][1],point[1]]);this.horizHairline.show();this.vertHairline.moveTo([point[0],this.props.graph.range[1][0]],[point[0],this.props.graph.range[1][1]]);this.vertHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();this.vertHairline.hide();}};}}function getUserInputFromSerializedState$b(serializedState){return serializedState.plot}function getStartUserInput$b(options){if(options.availableTypes.length===1){const graph=options.graph;const type=chooseType(options.availableTypes);if(type){return defaultPlotProps(type,graph)}}return DEFAULT_GRAPHER_PROPS.plot}function getCorrectUserInput$5(options){return options.correct}const WrappedGrapher=withDependencies(Grapher);var Grapher$1 = {name:"grapher",displayName:"Grapher",hidden:true,widget:WrappedGrapher,getUserInputFromSerializedState: getUserInputFromSerializedState$b,getStartUserInput: getStartUserInput$b,getCorrectUserInput: getCorrectUserInput$5};
1842
+ const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLine;function isFlipped(newCoord,oldCoord,line){const CCW=(a,b,c)=>{return (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])};return CCW(line[0],line[1],oldCoord)>0!==CCW(line[0],line[1],newCoord)>0}const typeSelectorStyle={padding:"5px 5px"};class FunctionGrapher extends React__namespace.Component{render(){const pointForCoord=(coord,i)=>{return jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:this.props.static,constraints:[Interactive2.MovablePoint.constraints.bound(),Interactive2.MovablePoint.constraints.snap(),coord=>{const isFunction=this._coords().every((otherCoord,j)=>{return i===j||!otherCoord||!kmath.number.equal(coord[0],otherCoord[0])});if(!isFunction){return false}if(this.props.model&&this.props.model.extraCoordConstraint){const extraConstraint=this.props.model.extraCoordConstraint;const proposedCoords=perseusCore.deepClone(this._coords());const oldCoord=perseusCore.deepClone(proposedCoords[i]);proposedCoords[i]=coord;return extraConstraint(coord,oldCoord,proposedCoords,this._asymptote(),this.props.graph)}return isFunction}],onMove:(newCoord,oldCoord)=>{let coords;const asymptote=this._asymptote();if(asymptote&&this.props.model.allowReflectOverAsymptote&&isFlipped(newCoord,oldCoord,asymptote)){coords=this._coords().map(coord=>{return kmath.point.reflectOverLine(coord,asymptote)});}else {coords=perseusCore.deepClone(this._coords());}coords[i]=newCoord;this.props.onChange({coords:coords});},showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},i)};const points=this._coords().map(pointForCoord);const box=this.props.graph.box;const imageDescription=this.props.graph.backgroundImage;let image=null;if(imageDescription.url){const scale=box[0]/interactiveSizes$1.defaultBoxSize;image=jsxRuntimeExports.jsx(SvgImage,{src:imageDescription.url,allowZoom:false,width:imageDescription.width,height:imageDescription.height,scale:scale});}return jsxRuntimeExports.jsx("div",{className:"perseus-widget "+"perseus-widget-grapher",style:{width:box[0],height:box[1],boxSizing:"initial"},children:jsxRuntimeExports.jsxs("div",{className:"graphie-container blank-background",style:{width:box[0],height:box[1]},children:[image,jsxRuntimeExports.jsxs(Graphie,{...this.props.graph,children:[this.props.model&&this.renderPlot(),this.props.model&&this.renderAsymptote(),this.props.model&&points]})]})})}constructor(...args){super(...args),this._coords=()=>{const props=this.props;const graph=props.graph;const defaultModelCoords=props.model&&maybePointsFromNormalized(props.model.defaultCoords,graph.range,graph.step,graph.snapStep);return props.coords||defaultModelCoords||null},this._asymptote=()=>{return this.props.asymptote},this.renderPlot=()=>{const model=this.props.model;const xRange=this.props.graph.range[0];const style={stroke:this.props.isMobile?KhanColors.BLUE_C:KhanColors.DYNAMIC,...this.props.isMobile?{"stroke-width":3}:{}};const coeffs=model.getCoefficients(this._coords(),this._asymptote());if(!coeffs){return}const functionProps=model.getPropsForCoeffs(coeffs,xRange);const Movable=movableTypeToComponent[model.movable];return React.createElement(Movable,{...functionProps,key:this.props.model.url,range:xRange,style:style})},this.renderAsymptote=()=>{const model=this.props.model;const graph=this.props.graph;const asymptote=this._asymptote();const showAsymptote=asymptote?.length>0;const dashed={strokeDasharray:"- "};return showAsymptote&&jsxRuntimeExports.jsx(MovableLine$2,{onMove:(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const newAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const proposedAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:asymptote.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:true,draw:null,extendLine:true,showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},`asymptoteCoord-${i}`))})};}}FunctionGrapher.defaultProps={graph:{range:[[-10,10],[-10,10]],step:[1,1]},coords:null,asymptote:null,isMobile:false};class Grapher extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"grapher",widgetSubType:"null",widgetId:this.props.widgetId}});}_getGridConfig(options){return options.step.map((step,i)=>{return Util.gridDimensionConfig(step,options.range[i],options.box[i],options.gridStep[i])})}_calculateMobileTickStep(gridStep,step,ranges){const tickStep=Util.constrainedTickStepsFromTickSteps(step,ranges);tickStep[0]=tickStep[0]/gridStep[0];tickStep[1]=tickStep[1]/gridStep[1];return tickStep}getPromptJSON(){return getPromptJSON$g(this.props)}getSerializedState(){const{userInput:_,correct:__,...rest}=this.props;return {...rest,plot:this.props.userInput}}render(){const availableTypes=this.props.static?[this.props.correct.type]:this.props.availableTypes;const type=this.props.userInput.type;const coords=this.props.userInput.coords;const asymptote="asymptote"in this.props.userInput?this.props.userInput.asymptote:undefined;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:availableTypes.map(typeToButton),onChange:this.handleActiveTypeChange})});const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const options={...this.props.graph,...getGridAndSnapSteps(this.props.graph,box[0]),gridConfig:this._getGridConfig({...this.props.graph,box:box,...getGridAndSnapSteps(this.props.graph,box[0])})};const grapherProps={graph:{box:box,range:options.range,step:options.step,snapStep:options.snapStep,backgroundImage:options.backgroundImage,options:options,setup:this._setupGraphie},onChange:this.handlePlotChanges,model:type&&perseusCore.GrapherUtil.functionForType(type),coords:coords,asymptote:asymptote,static:this.props.static,isMobile:this.props.apiOptions.isMobile,showTooltips:this.props.graph.showTooltips,showHairlines:this.showHairlines,hideHairlines:this.hideHairlines};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(FunctionGrapher,{...grapherProps}),availableTypes.length>1&&typeSelector]})}constructor(...args){super(...args),this.handlePlotChanges=newPlot=>{const plot={...this.props.userInput,...newPlot};this.props.handleUserInput(plot);this.props.trackInteraction();},this.handleActiveTypeChange=newType=>{const graph=this.props.graph;const plot={...this.props.userInput,...defaultPlotProps(newType,graph)};this.props.handleUserInput(plot);},this._setupGraphie=(graphie,options)=>{const isMobile=this.props.apiOptions.isMobile;if(options.markings==="graph"){graphie.graphInit({range:options.range,scale:options.gridConfig.map(e=>e.scale),axisArrows:"<->",labelFormat:function(s){return "\\small{"+s+"}"},gridStep:options.gridStep,snapStep:options.snapStep,tickStep:isMobile?this._calculateMobileTickStep(options.gridStep,options.step,options.range):options.gridConfig.map(e=>e.tickStep),labelStep:1,unityLabels:options.gridConfig.map(e=>e.unityLabel),isMobile:isMobile});graphie.label([0,options.range[1][1]],options.labels[1],isMobile?"below right":"above");graphie.label([options.range[0][1],0],options.labels[0],isMobile?"above left":"right");}else if(options.markings==="grid"){graphie.graphInit({range:options.range,scale:options.gridConfig.map(e=>e.scale),gridStep:options.gridStep,axes:false,ticks:false,labels:false,isMobile:isMobile});}else if(options.markings==="none"){graphie.init({range:options.range,scale:options.gridConfig.map(e=>e.scale)});}if(this.props.apiOptions.isMobile){const hairlineStyle={normalStyle:{strokeWidth:1}};this.horizHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.vertHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.vertHairline.attr({stroke:KhanColors.INTERACTIVE});this.vertHairline.hide();}},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.props.graph.range[0][0],point[1]],[this.props.graph.range[0][1],point[1]]);this.horizHairline.show();this.vertHairline.moveTo([point[0],this.props.graph.range[1][0]],[point[0],this.props.graph.range[1][1]]);this.vertHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();this.vertHairline.hide();}};}}function getUserInputFromSerializedState$b(serializedState){return serializedState.plot}function getStartUserInput$b(options){if(options.availableTypes.length===1){const graph=options.graph;const type=chooseType(options.availableTypes);if(type){return defaultPlotProps(type,graph)}}return DEFAULT_GRAPHER_PROPS.plot}function getCorrectUserInput$5(options){return options.correct}const WrappedGrapher=withDependencies(Grapher);var Grapher$1 = {name:"grapher",displayName:"Grapher",hidden:true,widget:WrappedGrapher,getUserInputFromSerializedState: getUserInputFromSerializedState$b,getStartUserInput: getStartUserInput$b,getCorrectUserInput: getCorrectUserInput$5};
1843
1843
 
1844
1844
  const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
1845
1845
 
@@ -1851,19 +1851,19 @@ const{updateQueryString}=Util;class Iframe extends React__namespace.Component{co
1851
1851
 
1852
1852
  const getPromptJSON$d=widgetData=>{return {type:"image",options:{altText:widgetData.alt,title:widgetData.title,caption:widgetData.caption,imageUrl:widgetData.backgroundImage.url}}};
1853
1853
 
1854
- var styles$g = {"titleContainer":"perseus_aAJy9Er3","infoAreaContainer":"perseus_a7ZnxMAZ","modalContainer":"perseus_-p2ghr1-","modalTitleContainer":"perseus_YxnjOOa7","modalPanelContainer":"perseus_ryDvI8uD","modalImageContainer":"perseus_yCoMyk8e","modalDescriptionContainer":"perseus_femvuTvR","modalCaptionContainer":"perseus_y4DO7MoR","spacerHorizontal":"perseus_fBhKbquh","spacerVertical":"perseus_9XgZ2QXH"};
1854
+ var styles$h = {"titleContainer":"perseus_aAJy9Er3","infoAreaContainer":"perseus_a7ZnxMAZ","modalContainer":"perseus_-p2ghr1-","modalTitleContainer":"perseus_YxnjOOa7","modalPanelContainer":"perseus_ryDvI8uD","modalImageContainer":"perseus_yCoMyk8e","modalDescriptionContainer":"perseus_femvuTvR","modalCaptionContainer":"perseus_y4DO7MoR","spacerHorizontal":"perseus_fBhKbquh","spacerVertical":"perseus_9XgZ2QXH"};
1855
1855
 
1856
1856
  function ExploreImageButton({hasCaption,onClick}){const context=React__namespace.useContext(PerseusI18nContext);if(!hasCaption){return jsxRuntimeExports.jsx(Button__default.default,{"aria-label":context.strings.imageExploreButtonAriaLabel,kind:"secondary",startIcon:infoIconBold__default.default,onClick:onClick,children:context.strings.imageExploreButton})}return jsxRuntimeExports.jsx(IconButton__default.default,{"aria-label":context.strings.imageExploreButtonAriaLabel,icon:infoIconBold__default.default,kind:"secondary",onClick:onClick,style:{flexShrink:0}})}
1857
1857
 
1858
- const VisibleIcon=()=>jsxRuntimeExports.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",className:aphrodite.css(styles$f.icon),children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsx("path",{id:"a",d:"M7.401 10.035c-1.424.748-2.599 1.905-3.544 "+"3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 "+"12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 "+"1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-"+"3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 "+"0 0 0 0 6z"})}),jsxRuntimeExports.jsxs("g",{fill:"none",fillRule:"evenodd",children:[jsxRuntimeExports.jsx("path",{fill:"none",d:"M0 0h24v24H0z"}),jsxRuntimeExports.jsx("mask",{id:"b",fill:"#fff",children:jsxRuntimeExports.jsx("use",{href:"#a"})}),jsxRuntimeExports.jsx("use",{fill:"#fff",fillRule:"nonzero",href:"#a"}),jsxRuntimeExports.jsx("g",{fill:"#fff",mask:"url(#b)",children:jsxRuntimeExports.jsx("path",{d:"M0 0h24v24H0z"})})]})]});const HiddenIcon=()=>jsxRuntimeExports.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",className:aphrodite.css(styles$f.icon),children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsx("path",{id:"a",d:"M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 "+"7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 "+"1.028c-.945-1.574-2.12-2.73-3.544-3.48.258."+"604.401 1.268.401 1.966 0 1.02-.305 "+"1.967-.828 2.757l2.535 2.536a1 1 0 0 "+"1-1.414 1.414l-12-12a1 1 0 0 1 "+"1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 "+"0-4.001-4.001l4 4.001zM6.072 8.486l2.976 "+"2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 "+"0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 "+"3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 "+"2.363-3.085 3.929-4z"})}),jsxRuntimeExports.jsxs("g",{fill:"none",fillRule:"evenodd",children:[jsxRuntimeExports.jsx("path",{fill:"none",d:"M0 0h24v24H0z"}),jsxRuntimeExports.jsx("mask",{id:"b",fill:"#fff",children:jsxRuntimeExports.jsx("use",{href:"#a"})}),jsxRuntimeExports.jsx("use",{fill:"#fff",fillRule:"nonzero",href:"#a"}),jsxRuntimeExports.jsx("g",{fill:"#fff",mask:"url(#b)",children:jsxRuntimeExports.jsx("path",{d:"M0 0h24v24H0z"})})]})]});const HUD=({message,enabled,onClick,fixedPosition=true})=>{let state;let icon;if(enabled){state=styles$f.enabled;icon=jsxRuntimeExports.jsx(VisibleIcon,{});}else {state=styles$f.disabled;icon=jsxRuntimeExports.jsx(HiddenIcon,{});}return jsxRuntimeExports.jsxs("button",{className:aphrodite.css(styles$f.hud,fixedPosition&&styles$f.hudFixedPosition,state),onClick:e=>{onClick();},children:[icon,message]})};const styles$f=aphrodite.StyleSheet.create({hud:{boxSizing:"border-box",height:36,padding:"9px 16px",borderRadius:18,fontFamily:boldFontFamily,fontSize:"15px",lineHeight:"18px",color:white,userSelect:"none",borderWidth:0},hudFixedPosition:{bottom:20,position:"fixed",right:20,zIndex:1},icon:{width:24,height:24,marginRight:8,marginTop:-3,verticalAlign:"middle"},enabled:{backgroundColor:warningColor,":hover":{backgroundColor:warningColorHover},":active":{backgroundColor:warningColorActive}},disabled:{backgroundColor:gray76,":hover":{backgroundColor:"#a1a5a9"},":active":{backgroundColor:gray68}}});
1858
+ const VisibleIcon=()=>jsxRuntimeExports.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",className:aphrodite.css(styles$g.icon),children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsx("path",{id:"a",d:"M7.401 10.035c-1.424.748-2.599 1.905-3.544 "+"3.48a1 1 0 0 1-1.714-1.03C4.325 8.849 7.652 7 "+"12 7c4.348 0 7.675 1.848 9.857 5.486a1 1 0 0 "+"1-1.714 1.028c-.945-1.574-2.12-2.73-3.544-"+"3.48a5 5 0 1 1-9.198 0zM12 15a3 3 0 1 0 0-6 3 3 "+"0 0 0 0 6z"})}),jsxRuntimeExports.jsxs("g",{fill:"none",fillRule:"evenodd",children:[jsxRuntimeExports.jsx("path",{fill:"none",d:"M0 0h24v24H0z"}),jsxRuntimeExports.jsx("mask",{id:"b",fill:"#fff",children:jsxRuntimeExports.jsx("use",{href:"#a"})}),jsxRuntimeExports.jsx("use",{fill:"#fff",fillRule:"nonzero",href:"#a"}),jsxRuntimeExports.jsx("g",{fill:"#fff",mask:"url(#b)",children:jsxRuntimeExports.jsx("path",{d:"M0 0h24v24H0z"})})]})]});const HiddenIcon=()=>jsxRuntimeExports.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",className:aphrodite.css(styles$g.icon),children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsx("path",{id:"a",d:"M8.794 7.38C9.791 7.127 10.86 7 12 7c4.348 0 "+"7.675 1.848 9.857 5.486a1 1 0 0 1-1.714 "+"1.028c-.945-1.574-2.12-2.73-3.544-3.48.258."+"604.401 1.268.401 1.966 0 1.02-.305 "+"1.967-.828 2.757l2.535 2.536a1 1 0 0 "+"1-1.414 1.414l-12-12a1 1 0 0 1 "+"1.414-1.414L8.794 7.38zm5.914 5.913a3 3 0 0 "+"0-4.001-4.001l4 4.001zM6.072 8.486l2.976 "+"2.976a3 3 0 0 0 3.49 3.49l1.579 1.58A5 5 0 "+"0 1 7.4 10.035c-1.424.747-2.599 1.904-3.544 "+"3.478a1 1 0 0 1-1.714-1.028c1.049-1.75 "+"2.363-3.085 3.929-4z"})}),jsxRuntimeExports.jsxs("g",{fill:"none",fillRule:"evenodd",children:[jsxRuntimeExports.jsx("path",{fill:"none",d:"M0 0h24v24H0z"}),jsxRuntimeExports.jsx("mask",{id:"b",fill:"#fff",children:jsxRuntimeExports.jsx("use",{href:"#a"})}),jsxRuntimeExports.jsx("use",{fill:"#fff",fillRule:"nonzero",href:"#a"}),jsxRuntimeExports.jsx("g",{fill:"#fff",mask:"url(#b)",children:jsxRuntimeExports.jsx("path",{d:"M0 0h24v24H0z"})})]})]});const HUD=({message,enabled,onClick,fixedPosition=true})=>{let state;let icon;if(enabled){state=styles$g.enabled;icon=jsxRuntimeExports.jsx(VisibleIcon,{});}else {state=styles$g.disabled;icon=jsxRuntimeExports.jsx(HiddenIcon,{});}return jsxRuntimeExports.jsxs("button",{className:aphrodite.css(styles$g.hud,fixedPosition&&styles$g.hudFixedPosition,state),onClick:e=>{onClick();},children:[icon,message]})};const styles$g=aphrodite.StyleSheet.create({hud:{boxSizing:"border-box",height:36,padding:"9px 16px",borderRadius:18,fontFamily:boldFontFamily,fontSize:"15px",lineHeight:"18px",color:white,userSelect:"none",borderWidth:0},hudFixedPosition:{bottom:20,position:"fixed",right:20,zIndex:1},icon:{width:24,height:24,marginRight:8,marginTop:-3,verticalAlign:"middle"},enabled:{backgroundColor:warningColor,":hover":{backgroundColor:warningColorHover},":active":{backgroundColor:warningColorActive}},disabled:{backgroundColor:gray76,":hover":{backgroundColor:"#a1a5a9"},":active":{backgroundColor:gray68}}});
1859
1859
 
1860
1860
  const BASE_ICON_SIZE=10;class Icon extends React__namespace.Component{render(){const{color,pathClassName,className,title,style,alt}=this.props;let{icon,size}=this.props;let units="";if(typeof icon==="string"){icon={path:icon,width:BASE_ICON_SIZE,height:BASE_ICON_SIZE};}if(typeof size!=="number"){size=1;units="em";}const height=size;const width=height/icon.height*icon.width;const xMin=0;const yMin=0;const focusable=!!this.props.focusable;return jsxRuntimeExports.jsxs("svg",{role:"img",alt:alt,"aria-label":title,"aria-hidden":title?null:true,className:className,style:style,focusable:focusable.toString(),width:width+units,height:height+units,viewBox:`${xMin} ${yMin} ${icon.width} ${icon.height}`,children:[!!title&&jsxRuntimeExports.jsx("title",{children:title}),jsxRuntimeExports.jsx("path",{className:pathClassName,fill:color,d:icon.path})]})}}Icon.defaultProps={color:"currentColor"};
1861
1861
 
1862
- const InfoTipBase=props=>{return jsxRuntimeExports.jsx(Tooltip__default.default,{content:jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{style:styles$e.body,children:props.children}),placement:"right",children:jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{size:"small",icon:questionIcon__default.default,style:styles$e.spacingLeft})})};const styles$e=aphrodite.StyleSheet.create({spacingLeft:{marginInlineStart:wonderBlocksTokens.spacing.xxxSmall_4},body:{padding:wonderBlocksTokens.spacing.medium_16}});
1862
+ const InfoTipBase=props=>{return jsxRuntimeExports.jsx(Tooltip__default.default,{content:jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{style:styles$f.body,children:props.children}),placement:"right",children:jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{size:"small",icon:questionIcon__default.default,style:styles$f.spacingLeft})})};const styles$f=aphrodite.StyleSheet.create({spacingLeft:{marginInlineStart:wonderBlocksTokens.spacing.xxxSmall_4},body:{padding:wonderBlocksTokens.spacing.medium_16}});
1863
1863
 
1864
1864
  class InfoTip extends React__namespace.Component{componentDidMount(){this.setState({didMount:true});}render(){if(this.state.didMount){return jsxRuntimeExports.jsx(InfoTipBase,{...this.props})}return jsxRuntimeExports.jsx("div",{})}constructor(...args){super(...args),this.state={didMount:false};}}
1865
1865
 
1866
- class MultiButtonGroup extends React__namespace.Component{focus(){this.buttonContainerRef.current?.focus();return true}render(){const values=this.props.values||[];const buttons=this.props.buttons.map((button,i)=>{const selected=values.indexOf(button.value)>=0;return jsxRuntimeExports.jsx("button",{title:button.title,type:"button",id:""+i,ref:"button"+i,className:aphrodite.css(styles$d.buttonStyle,selected&&styles$d.selectedStyle),onClick:()=>this.toggleSelect(button.value),children:button.content||""+button.value},""+i)});const outerStyle={display:"inline-block"};return jsxRuntimeExports.jsx("div",{style:outerStyle,ref:this.buttonContainerRef,children:buttons})}constructor(...args){super(...args),this.buttonContainerRef=React__namespace.createRef(),this.toggleSelect=newValue=>{const values=(this.props.values||[]).slice(0);const allowEmpty=this.props.allowEmpty;if(values.indexOf(newValue)>=0&&(values.length>1||allowEmpty)){values.splice(values.indexOf(newValue),1);}else {if(values.indexOf(newValue)<0){values.push(newValue);}}this.props.onChange(values);};}}MultiButtonGroup.defaultProps={values:[],allowEmpty:true};const styles$d=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"}});
1866
+ class MultiButtonGroup extends React__namespace.Component{focus(){this.buttonContainerRef.current?.focus();return true}render(){const values=this.props.values||[];const buttons=this.props.buttons.map((button,i)=>{const selected=values.indexOf(button.value)>=0;return jsxRuntimeExports.jsx("button",{title:button.title,type:"button",id:""+i,ref:"button"+i,className:aphrodite.css(styles$e.buttonStyle,selected&&styles$e.selectedStyle),onClick:()=>this.toggleSelect(button.value),children:button.content||""+button.value},""+i)});const outerStyle={display:"inline-block"};return jsxRuntimeExports.jsx("div",{style:outerStyle,ref:this.buttonContainerRef,children:buttons})}constructor(...args){super(...args),this.buttonContainerRef=React__namespace.createRef(),this.toggleSelect=newValue=>{const values=(this.props.values||[]).slice(0);const allowEmpty=this.props.allowEmpty;if(values.indexOf(newValue)>=0&&(values.length>1||allowEmpty)){values.splice(values.indexOf(newValue),1);}else {if(values.indexOf(newValue)<0){values.push(newValue);}}this.props.onChange(values);};}}MultiButtonGroup.defaultProps={values:[],allowEmpty:true};const styles$e=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"}});
1867
1867
 
1868
1868
  function isPiMultiple(value){if(Number.isInteger(value)){return false}return value%Math.PI===0||value%(Math.PI/2)===0||value%(Math.PI/3)===0||value%(Math.PI/4)===0||value%(Math.PI/6)===0}
1869
1869
 
@@ -1892,21 +1892,21 @@ var components = /*#__PURE__*/Object.freeze({
1892
1892
 
1893
1893
  const GifControlsButton=({isPlaying,onToggle})=>{const strings=usePerseusI18n().strings;return jsxRuntimeExports.jsx(Button__default.default,{"aria-label":isPlaying?strings.gifPauseButtonLabel:strings.gifPlayButtonLabel,kind:"secondary",startIcon:isPlaying?pauseIcon__default.default:playIcon__default.default,onClick:onToggle,style:{width:"fit-content"},children:isPlaying?strings.gifPauseButtonLabel:strings.gifPlayButtonLabel})};
1894
1894
 
1895
- const MODAL_HEIGHT=568;function ExploreImageModalContent({backgroundImage,scale:contentScale,caption,alt,longDescription,linterContext,apiOptions,box,labels,range,captionId,longDescId}){const[isGifPlaying,setIsGifPlaying]=React__namespace.useState(false);const context=React__namespace.useContext(PerseusI18nContext);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);const imageIsSvg=isSvg(backgroundImage.url);let scale=1;if(backgroundImage.width&&backgroundImage.height){scale=imageIsSvg?Math.max(contentScale,2):Math.max(contentScale,1);}let height=backgroundImage.height;let width=backgroundImage.width;if(backgroundImage.height&&backgroundImage.width){width=backgroundImage.width;height=backgroundImage.height;const maxScale=MODAL_HEIGHT/backgroundImage.height;scale=Math.min(scale,maxScale);}return jsxRuntimeExports.jsxs("div",{className:styles$g.modalPanelContainer,children:[jsxRuntimeExports.jsx("div",{className:styles$g.modalImageContainer,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,allowZoom:false,alt:caption===alt?"":alt,width:width,height:height,scale:scale,preloader:apiOptions.imagePreloader,extraGraphie:{box:box,range:range,labels:labels??[]},zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,setAssetStatus:setAssetStatus,isGifPlaying:imageIsGif?isGifPlaying:undefined,onGifLoop:imageIsGif?()=>setIsGifPlaying(false):undefined})})}),jsxRuntimeExports.jsxs("div",{className:`perseus-image-modal-description ${styles$g.modalDescriptionContainer}`,children:[imageIsGif&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(GifControlsButton,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),jsxRuntimeExports.jsx("div",{className:styles$g.spacerVertical})]}),caption&&jsxRuntimeExports.jsx("div",{id:captionId,className:styles$g.modalCaptionContainer,children:jsxRuntimeExports.jsx(Renderer,{content:caption,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),jsxRuntimeExports.jsx(wonderBlocksTypography.Heading,{size:"large",tag:"h2",style:wbStyles$1.descriptionHeading,children:context.strings.imageDescriptionLabel}),jsxRuntimeExports.jsx("div",{id:longDescId,children:jsxRuntimeExports.jsx(Renderer,{content:longDescription,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})})]})]})}const wbStyles$1={descriptionHeading:{marginBlockEnd:wonderBlocksTokens.sizing.size_160}};
1895
+ const MODAL_HEIGHT=568;function ExploreImageModalContent({backgroundImage,scale:contentScale,caption,alt,longDescription,linterContext,apiOptions,box,labels,range,captionId,longDescId}){const[isGifPlaying,setIsGifPlaying]=React__namespace.useState(false);const context=React__namespace.useContext(PerseusI18nContext);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);const imageIsSvg=isSvg(backgroundImage.url);let scale=1;if(backgroundImage.width&&backgroundImage.height){scale=imageIsSvg?Math.max(contentScale,2):Math.max(contentScale,1);}let height=backgroundImage.height;let width=backgroundImage.width;if(backgroundImage.height&&backgroundImage.width){width=backgroundImage.width;height=backgroundImage.height;const maxScale=MODAL_HEIGHT/backgroundImage.height;scale=Math.min(scale,maxScale);}return jsxRuntimeExports.jsxs("div",{className:styles$h.modalPanelContainer,children:[jsxRuntimeExports.jsx("div",{className:styles$h.modalImageContainer,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,allowZoom:false,alt:caption===alt?"":alt,width:width,height:height,scale:scale,extraGraphie:{box:box,range:range,labels:labels??[]},zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,setAssetStatus:setAssetStatus,isGifPlaying:imageIsGif?isGifPlaying:undefined,onGifLoop:imageIsGif?()=>setIsGifPlaying(false):undefined})})}),jsxRuntimeExports.jsxs("div",{className:`perseus-image-modal-description ${styles$h.modalDescriptionContainer}`,children:[imageIsGif&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(GifControlsButton,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),jsxRuntimeExports.jsx("div",{className:styles$h.spacerVertical})]}),caption&&jsxRuntimeExports.jsx("div",{id:captionId,className:styles$h.modalCaptionContainer,children:jsxRuntimeExports.jsx(Renderer,{content:caption,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),jsxRuntimeExports.jsx(wonderBlocksTypography.Heading,{size:"large",tag:"h2",style:wbStyles$1.descriptionHeading,children:context.strings.imageDescriptionLabel}),jsxRuntimeExports.jsx("div",{id:longDescId,children:jsxRuntimeExports.jsx(Renderer,{content:longDescription,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})})]})]})}const wbStyles$1={descriptionHeading:{marginBlockEnd:wonderBlocksTokens.sizing.size_160}};
1896
1896
 
1897
- const ExploreImageModal=props=>{const context=React__namespace.default.useContext(PerseusI18nContext);const uniqueId=React__namespace.default.useId();const captionId=`${uniqueId}-caption`;const longDescId=`${uniqueId}-long-desc`;const titleText=props.title||context.strings.imageAlternativeTitle;const title=jsxRuntimeExports.jsx("h1",{className:`perseus-image-modal-title ${styles$g.modalTitleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:titleText,apiOptions:props.apiOptions,linterContext:props.linterContext,strings:context.strings})});return jsxRuntimeExports.jsx("div",{className:`framework-perseus ${styles$g.modalContainer}`,children:jsxRuntimeExports.jsx(wonderBlocksModal.FlexibleDialog,{title:title,content:jsxRuntimeExports.jsx(ExploreImageModalContent,{...props,captionId:captionId,longDescId:longDescId}),"aria-describedby":props.caption?`${captionId} ${longDescId}`:longDescId,styles:{root:wbStyles.root}})})};const wbStyles={root:{borderRadius:wonderBlocksTokens.sizing.size_120,maxWidth:"100%"}};
1897
+ const ExploreImageModal=props=>{const context=React__namespace.default.useContext(PerseusI18nContext);const uniqueId=React__namespace.default.useId();const captionId=`${uniqueId}-caption`;const longDescId=`${uniqueId}-long-desc`;const titleText=props.title||context.strings.imageAlternativeTitle;const title=jsxRuntimeExports.jsx("h1",{className:`perseus-image-modal-title ${styles$h.modalTitleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:titleText,apiOptions:props.apiOptions,linterContext:props.linterContext,strings:context.strings})});return jsxRuntimeExports.jsx("div",{className:`framework-perseus ${styles$h.modalContainer}`,children:jsxRuntimeExports.jsx(wonderBlocksModal.FlexibleDialog,{title:title,content:jsxRuntimeExports.jsx(ExploreImageModalContent,{...props,captionId:captionId,longDescId:longDescId}),"aria-describedby":props.caption?`${captionId} ${longDescId}`:longDescId,styles:{root:wbStyles.root}})})};const wbStyles={root:{borderRadius:wonderBlocksTokens.sizing.size_120,maxWidth:"100%"}};
1898
1898
 
1899
1899
  const GifControlsIcon=({isPlaying,onToggle})=>{const strings=usePerseusI18n().strings;return jsxRuntimeExports.jsx(IconButton__default.default,{icon:isPlaying?pauseIcon__default.default:playIcon__default.default,kind:"secondary","aria-label":isPlaying?strings.gifPauseButtonLabel:strings.gifPlayButtonLabel,onClick:onToggle,style:{flexShrink:0}})};
1900
1900
 
1901
- const ImageInfoArea=props=>{const{backgroundImage,caption,longDescription,apiOptions,linterContext,isGifPlaying,setIsGifPlaying}=props;const context=React__namespace.useContext(PerseusI18nContext);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);return jsxRuntimeExports.jsxs("div",{className:styles$g.infoAreaContainer,children:[imageIsGif&&jsxRuntimeExports.jsx(GifControlsIcon,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),imageIsGif&&longDescription&&jsxRuntimeExports.jsx("div",{className:styles$g.spacerHorizontal}),longDescription&&jsxRuntimeExports.jsx(wonderBlocksModal.ModalLauncher,{modal:jsxRuntimeExports.jsx(ExploreImageModal,{...props}),children:({openModal})=>jsxRuntimeExports.jsx(ExploreImageButton,{hasCaption:!!caption,onClick:openModal})}),caption&&jsxRuntimeExports.jsx("figcaption",{className:"perseus-image-caption",children:jsxRuntimeExports.jsx(Renderer,{content:caption,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})})]})};
1901
+ const ImageInfoArea=props=>{const{backgroundImage,caption,longDescription,apiOptions,linterContext,isGifPlaying,setIsGifPlaying}=props;const context=React__namespace.useContext(PerseusI18nContext);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);return jsxRuntimeExports.jsxs("div",{className:styles$h.infoAreaContainer,children:[imageIsGif&&jsxRuntimeExports.jsx(GifControlsIcon,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),imageIsGif&&longDescription&&jsxRuntimeExports.jsx("div",{className:styles$h.spacerHorizontal}),longDescription&&jsxRuntimeExports.jsx(wonderBlocksModal.ModalLauncher,{modal:jsxRuntimeExports.jsx(ExploreImageModal,{...props}),children:({openModal})=>jsxRuntimeExports.jsx(ExploreImageButton,{hasCaption:!!caption,onClick:openModal})}),caption&&jsxRuntimeExports.jsx("figcaption",{className:"perseus-image-caption",children:jsxRuntimeExports.jsx(Renderer,{content:caption,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})})]})};
1902
1902
 
1903
- const ImageComponent=props=>{const{apiOptions,alt,backgroundImage,box,caption,longDescription,decorative,linterContext,labels,range,title,trackInteraction,widgetId}=props;const context=React__namespace.useContext(PerseusI18nContext);const{analytics}=useDependencies();const[isGifPlaying,setIsGifPlaying]=React__namespace.useState(false);wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"image",widgetId:widgetId}});});React__namespace.useEffect(()=>{setIsGifPlaying(false);},[backgroundImage.url]);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);let scale=props.scale;if(scale<=0||scale===Infinity||scale===-Infinity){scale=1;}const svgImage=jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,apiOptions:apiOptions,width:backgroundImage.width,height:backgroundImage.height,scale:scale,preloader:apiOptions.imagePreloader,extraGraphie:{box:box,range:range,labels:labels},trackInteraction:trackInteraction,zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,allowZoom:!decorative&&!imageIsGif,alt:decorative||caption===alt?"":alt,setAssetStatus:setAssetStatus,isGifPlaying:imageIsGif?isGifPlaying:undefined,onGifLoop:imageIsGif?()=>setIsGifPlaying(false):undefined})});const maxWidth=backgroundImage.width?backgroundImage.width*scale:undefined;const width=maxWidth?undefined:"fit-content";if(decorative){return jsxRuntimeExports.jsx("figure",{className:"perseus-image-widget",style:{maxWidth:maxWidth,width:width},children:svgImage})}return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:maxWidth,width: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,(imageIsGif||caption||longDescription)&&jsxRuntimeExports.jsx(ImageInfoArea,{isGifPlaying:isGifPlaying,setIsGifPlaying:setIsGifPlaying,...props})]})};
1903
+ const ImageComponent=props=>{const{apiOptions,alt,backgroundImage,box,caption,longDescription,decorative,linterContext,labels,range,title,trackInteraction,widgetId}=props;const context=React__namespace.useContext(PerseusI18nContext);const{analytics}=useDependencies();const[isGifPlaying,setIsGifPlaying]=React__namespace.useState(false);wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"image",widgetId:widgetId}});});React__namespace.useEffect(()=>{setIsGifPlaying(false);},[backgroundImage.url]);if(!backgroundImage.url){return null}const imageIsGif=isGif(backgroundImage.url);let scale=props.scale;if(scale<=0||scale===Infinity||scale===-Infinity){scale=1;}const svgImage=jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:backgroundImage.url,apiOptions:apiOptions,width:backgroundImage.width,height:backgroundImage.height,scale:scale,extraGraphie:{box:box,range:range,labels:labels},trackInteraction:trackInteraction,zoomToFullSizeOnMobile:apiOptions.isMobile,constrainHeight:apiOptions.isMobile,allowFullBleed:apiOptions.isMobile,allowZoom:!decorative&&!imageIsGif,alt:decorative||caption===alt?"":alt,setAssetStatus:setAssetStatus,isGifPlaying:imageIsGif?isGifPlaying:undefined,onGifLoop:imageIsGif?()=>setIsGifPlaying(false):undefined})});const maxWidth=backgroundImage.width?backgroundImage.width*scale:undefined;const width=maxWidth?undefined:"fit-content";if(decorative){return jsxRuntimeExports.jsx("figure",{className:"perseus-image-widget",style:{maxWidth:maxWidth,width:width},children:svgImage})}return jsxRuntimeExports.jsxs("figure",{className:"perseus-image-widget",style:{maxWidth:maxWidth,width:width},children:[title&&jsxRuntimeExports.jsx("div",{className:`perseus-image-title ${styles$h.titleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:title,apiOptions:apiOptions,linterContext:linterContext,strings:context.strings})}),svgImage,(imageIsGif||caption||longDescription)&&jsxRuntimeExports.jsx(ImageInfoArea,{isGifPlaying:isGifPlaying,setIsGifPlaying:setIsGifPlaying,...props})]})};
1904
1904
 
1905
1905
  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,scale:1,labels:[],alt:"",longDescription:"",decorative:false,caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
1906
1906
 
1907
1907
  const getPromptJSON$c=()=>{return getUnsupportedPromptJSON("interaction")};
1908
1908
 
1909
- const Label=Graphie.Label;const Line$2=Graphie.Line;const MovablePoint$2=Graphie.MovablePoint;const MovableLine$1=Graphie.MovableLine;const Plot=Graphie.Plot;const PlotParametric=Graphie.PlotParametric;const Point=Graphie.Point;const Rect=Graphie.Rect;const{unescapeMathMode}=Util;const KAShashFunc=(expr,options)=>{options=options||{};let result=expr+"||"+options.decimal_separator+"||";const functions=options.functions;const functionsLength=functions?functions.length:0;for(let i=0;i<functionsLength;i++){result+=functions[i]+"|";}return result};const _parseCache=Object.create(null);const KASparse=(expr,options)=>{const hash=KAShashFunc(expr,options);let cached=_parseCache[hash];if(cached){return cached}cached=KAS__namespace.parse(expr,options);_parseCache[hash]=cached;return cached};const _compileCache=Object.create(null);const KAScompile=(expr,options)=>{const hash=KAShashFunc(expr,options);let cached=_compileCache[hash];if(cached){return cached}const parsed=KAS__namespace.parse(expr,options).expr;cached=parsed?parsed.compile():function(){return 0};_compileCache[hash]=cached;return cached};class Interaction extends React__namespace.Component{UNSAFE_componentWillReceiveProps(nextProps){if(!___default.default.isEqual(this.props.elements,nextProps.elements)){this.setState({variables:_getInitialVariables(nextProps.elements),functions:_getInitialFunctions(nextProps.elements)});}}getPromptJSON(){return getPromptJSON$c()}render(){const range=this.props.graph.range;let labels=this.props.graph.labels;if(this.props.graph.markings==="graph"){labels=this.props.graph.labels.map(label=>label.startsWith("$")&&label.endsWith("$")?label.slice(1,-1):label);}return jsxRuntimeExports.jsxs(Graphie,{box:this.props.graph.box,range:this.props.graph.range,options:this.props.graph,setup:this._setupGraphie,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,children:[this.props.graph.markings==="graph"&&jsxRuntimeExports.jsx(Label,{coord:[0,range[1][1]],text:labels[1],direction:"above"}),this.props.graph.markings==="graph"&&jsxRuntimeExports.jsx(Label,{coord:[range[0][1],0],text:labels[0],direction:"right"}),___default.default.map(this.props.elements,function(element,n){if(element.type==="point"){return jsxRuntimeExports.jsx(Point,{coord:[this._eval(element.options.coordX),this._eval(element.options.coordY)],color:element.options.color},element.key)}if(element.type==="line"){const start=[this._eval(element.options.startX),this._eval(element.options.startY)];const end=[this._eval(element.options.endX),this._eval(element.options.endY)];return jsxRuntimeExports.jsx(Line$2,{start:start,end:end,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,arrows:element.options.arrows}},element.key)}if(element.type==="movable-point"){const constraints=[coord=>{const coordX=Math.max(this._eval(element.options.constraintXMin),Math.min(this._eval(element.options.constraintXMax),coord[0]));const coordY=Math.max(this._eval(element.options.constraintYMin),Math.min(this._eval(element.options.constraintYMax),coord[1]));return [coordX,coordY]}];if(element.options.constraint==="snap"){constraints.push(MovablePoint$2.constraints.snap(element.options.snap));}else if(element.options.constraint==="x"){constraints.push(coord=>{return [this._eval(element.options.constraintFn,{y:coord[1]}),coord[1]]});}else if(element.options.constraint==="y"){constraints.push(coord=>{return [coord[0],this._eval(element.options.constraintFn,{x:coord[0]})]});}return jsxRuntimeExports.jsx(MovablePoint$2,{coord:[this.state.variables["x_"+element.options.varSubscript],this.state.variables["y_"+element.options.varSubscript]],constraints:constraints,foo_x:element.options.constraint,foo_y:element.options.constraintFn,foo_z:element.options.snap,onMove:___default.default.partial(this._updatePointLocation,element.options.varSubscript)},element.key)}if(element.type==="movable-line"){const constraints=[coord=>{const coordX=Math.max(this._eval(element.options.constraintXMin),Math.min(this._eval(element.options.constraintXMax),coord[0]));const coordY=Math.max(this._eval(element.options.constraintYMin),Math.min(this._eval(element.options.constraintYMax),coord[1]));return [coordX,coordY]}];if(element.options.constraint==="snap"){constraints.push(MovablePoint$2.constraints.snap(element.options.snap));}else if(element.options.constraint==="x"){constraints.push(coord=>{return [this._eval(element.options.constraintFn,{y:coord[1]}),coord[1]]});}else if(element.options.constraint==="y"){constraints.push(coord=>{return [coord[0],this._eval(element.options.constraintFn,{x:coord[0]})]});}const start=[this.state.variables["x_"+element.options.startSubscript],this.state.variables["y_"+element.options.startSubscript]];const end=[this.state.variables["x_"+element.options.endSubscript],this.state.variables["y_"+element.options.endSubscript]];return jsxRuntimeExports.jsxs(MovableLine$1,{constraints:constraints,onMove:___default.default.bind(this._updateLineLocation,this,element.options),foo_x:element.options.constraint,foo_y:element.options.constraintFn,foo_z:element.options.snap,children:[jsxRuntimeExports.jsx(MovablePoint$2,{coord:start,static:true,normalStyle:{stroke:"none",fill:"none"}}),jsxRuntimeExports.jsx(MovablePoint$2,{coord:end,static:true,normalStyle:{stroke:"none",fill:"none"}})]},element.key)}if(element.type==="function"){const fn=x=>{return this._eval(element.options.value,{x:x})};const vars=___default.default.without(this._extractVars(KASparse(element.options.value).expr),"x");const varValues=___default.default.object(vars,___default.default.map(vars,v=>this.state.variables[v]));const range=[this._eval(element.options.rangeMin,this.state.variables),this._eval(element.options.rangeMax,this.state.variables)];return jsxRuntimeExports.jsx(Plot,{fn:fn,foo_fn:element.options.value,foo_varvalues:varValues,range:range,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,plotPoints:100}},element.key)}if(element.type==="parametric"){const fn=t=>{return [this._eval(element.options.x,{t:t}),this._eval(element.options.y,{t:t})]};const vars=___default.default.without(this._extractVars(KASparse(element.options.x).expr).concat(this._extractVars(KASparse(element.options.y).expr)),"t");const varValues=___default.default.object(vars,___default.default.map(vars,v=>this.state.variables[v]));const range=[this._eval(element.options.rangeMin,this.state.variables),this._eval(element.options.rangeMax,this.state.variables)];return jsxRuntimeExports.jsx(PlotParametric,{fn:fn,foo_fnx:element.options.x,foo_fny:element.options.y,foo_varvalues:varValues,range:range,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,plotPoints:100}},element.key)}if(element.type==="label"){const coord=[this._eval(element.options.coordX),this._eval(element.options.coordY)];return jsxRuntimeExports.jsx(Label,{coord:coord,text:unescapeMathMode(element.options.label),style:{color:element.options.color}},n+1)}if(element.type==="rectangle"){return jsxRuntimeExports.jsx(Rect,{x:this._eval(element.options.coordX),y:this._eval(element.options.coordY),width:___default.default.max([this._eval(element.options.width),0]),height:___default.default.max([this._eval(element.options.height),0]),style:{stroke:"none",fill:element.options.color}},n+1)}},this)]})}constructor(...args){super(...args),this.isWidget=true,this.state={variables:_getInitialVariables(this.props.elements),functions:_getInitialFunctions(this.props.elements)},this._setupGraphie=(graphie,options)=>{graphie.graphInit(___default.default.extend({},options,{grid:___default.default.contains(["graph","grid"],this.props.graph.markings),axes:___default.default.contains(["graph"],this.props.graph.markings),ticks:___default.default.contains(["graph"],this.props.graph.markings),labels:___default.default.contains(["graph"],this.props.graph.markings),labelFormat:function(s){return "\\small{"+s+"}"},axisArrows:"<->",unityLabels:false}));},this._updatePointLocation=(subscript,coord)=>{const variables=___default.default.clone(this.state.variables);variables["x_"+subscript]=coord[0];variables["y_"+subscript]=coord[1];this.setState({variables:variables});this.props.trackInteraction();},this._updateLineLocation=(options,startCoord)=>{const xDiff=this._eval("("+options.endX+")-("+options.startX+")");const yDiff=this._eval("("+options.endY+")-("+options.startY+")");const endCoord=kmath.vector.add(startCoord,[xDiff,yDiff]);const variables=___default.default.clone(this.state.variables);variables["x_"+options.startSubscript]=startCoord[0];variables["y_"+options.startSubscript]=startCoord[1];variables["x_"+options.endSubscript]=endCoord[0];variables["y_"+options.endSubscript]=endCoord[1];this.setState({variables:variables});this.props.trackInteraction();},this._eval=(expression,variables)=>{const func=KAScompile(expression,{functions:this.state.functions});const compiledVars=___default.default.extend({},this.state.variables,variables);___default.default.each(___default.default.keys(compiledVars),name=>{if(___default.default.isString(compiledVars[name])){const func=KAScompile(compiledVars[name],{functions:this.state.functions});compiledVars[name]=function(x){return func(___default.default.extend({},compiledVars,{x:x}))};}});return func(compiledVars)||0},this._extractVars=expr=>{if(expr==null){return []}let vars=[];___default.default.each(expr.args(),function(arg){if(arg&&arg.constructor.name==="Expr"){vars=vars.concat(this._extractVars(arg));}},this);if(expr.name()==="Var"){vars.push(expr.prettyPrint());}return vars};}}Interaction.defaultProps={graph:{box:[400,400],labels:["x","y"],range:[[-10,10],[-10,10]],tickStep:[1,1],gridStep:[1,1],markings:"graph"},elements:[]};const _getInitialVariables=elements=>{const variables={};___default.default.each(___default.default.where(elements,{type:"movable-point"}),element=>{const subscript=element.options.varSubscript;const startXExpr=KASparse(element.options.startX||"0").expr;const startYExpr=KASparse(element.options.startY||"0").expr;let startX=0;let startY=0;if(startXExpr){startX=startXExpr.eval({})||0;}if(startYExpr){startY=startYExpr.eval({})||0;}variables["x_"+subscript]=startX;variables["y_"+subscript]=startY;});___default.default.each(___default.default.where(elements,{type:"movable-line"}),element=>{const startSubscript=element.options.startSubscript;const endSubscript=element.options.endSubscript;const startXExpr=KASparse(element.options.startX||"0").expr;const startYExpr=KASparse(element.options.startY||"0").expr;const endXExpr=KASparse(element.options.endX||"0").expr;const endYExpr=KASparse(element.options.endY||"0").expr;let startX=0;let startY=0;let endX=0;let endY=0;if(startXExpr){startX=startXExpr.eval({})||0;}if(startYExpr){startY=startYExpr.eval({})||0;}if(endXExpr){endX=endXExpr.eval({})||0;}if(endYExpr){endY=endYExpr.eval({})||0;}variables["x_"+startSubscript]=startX;variables["y_"+startSubscript]=startY;variables["x_"+endSubscript]=endX;variables["y_"+endSubscript]=endY;});___default.default.each(___default.default.where(elements,{type:"function"}),element=>{variables[element.options.funcName]=element.options.value;});return variables};const _getInitialFunctions=elements=>{return ___default.default.map(___default.default.where(elements,{type:"function"}),element=>element.options.funcName)};var Interactive = {name:"interaction",displayName:"Interaction",widget:Interaction,hidden:true};
1909
+ const Label=Graphie.Label;const Line$2=Graphie.Line;const MovablePoint$2=Graphie.MovablePoint;const MovableLine$1=Graphie.MovableLine;const Plot=Graphie.Plot;const PlotParametric=Graphie.PlotParametric;const Point=Graphie.Point;const Rect=Graphie.Rect;const{unescapeMathMode}=Util;const KAShashFunc=(expr,options)=>{options=options||{};let result=expr+"||"+options.decimal_separator+"||";const functions=options.functions;const functionsLength=functions?functions.length:0;for(let i=0;i<functionsLength;i++){result+=functions[i]+"|";}return result};const _parseCache=Object.create(null);const KASparse=(expr,options)=>{const hash=KAShashFunc(expr,options);let cached=_parseCache[hash];if(cached){return cached}cached=KAS__namespace.parse(expr,options);_parseCache[hash]=cached;return cached};const _compileCache=Object.create(null);const KAScompile=(expr,options)=>{const hash=KAShashFunc(expr,options);let cached=_compileCache[hash];if(cached){return cached}const parsed=KAS__namespace.parse(expr,options).expr;cached=parsed?parsed.compile():function(){return 0};_compileCache[hash]=cached;return cached};class Interaction extends React__namespace.Component{UNSAFE_componentWillReceiveProps(nextProps){if(!___default.default.isEqual(this.props.elements,nextProps.elements)){this.setState({variables:_getInitialVariables(nextProps.elements),functions:_getInitialFunctions(nextProps.elements)});}}getPromptJSON(){return getPromptJSON$c()}render(){const range=this.props.graph.range;let labels=this.props.graph.labels;if(this.props.graph.markings==="graph"){labels=this.props.graph.labels.map(label=>label.startsWith("$")&&label.endsWith("$")?label.slice(1,-1):label);}return jsxRuntimeExports.jsxs(Graphie,{box:this.props.graph.box,range:this.props.graph.range,options:this.props.graph,setup:this._setupGraphie,children:[this.props.graph.markings==="graph"&&jsxRuntimeExports.jsx(Label,{coord:[0,range[1][1]],text:labels[1],direction:"above"}),this.props.graph.markings==="graph"&&jsxRuntimeExports.jsx(Label,{coord:[range[0][1],0],text:labels[0],direction:"right"}),___default.default.map(this.props.elements,function(element,n){if(element.type==="point"){return jsxRuntimeExports.jsx(Point,{coord:[this._eval(element.options.coordX),this._eval(element.options.coordY)],color:element.options.color},element.key)}if(element.type==="line"){const start=[this._eval(element.options.startX),this._eval(element.options.startY)];const end=[this._eval(element.options.endX),this._eval(element.options.endY)];return jsxRuntimeExports.jsx(Line$2,{start:start,end:end,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,arrows:element.options.arrows}},element.key)}if(element.type==="movable-point"){const constraints=[coord=>{const coordX=Math.max(this._eval(element.options.constraintXMin),Math.min(this._eval(element.options.constraintXMax),coord[0]));const coordY=Math.max(this._eval(element.options.constraintYMin),Math.min(this._eval(element.options.constraintYMax),coord[1]));return [coordX,coordY]}];if(element.options.constraint==="snap"){constraints.push(MovablePoint$2.constraints.snap(element.options.snap));}else if(element.options.constraint==="x"){constraints.push(coord=>{return [this._eval(element.options.constraintFn,{y:coord[1]}),coord[1]]});}else if(element.options.constraint==="y"){constraints.push(coord=>{return [coord[0],this._eval(element.options.constraintFn,{x:coord[0]})]});}return jsxRuntimeExports.jsx(MovablePoint$2,{coord:[this.state.variables["x_"+element.options.varSubscript],this.state.variables["y_"+element.options.varSubscript]],constraints:constraints,foo_x:element.options.constraint,foo_y:element.options.constraintFn,foo_z:element.options.snap,onMove:___default.default.partial(this._updatePointLocation,element.options.varSubscript)},element.key)}if(element.type==="movable-line"){const constraints=[coord=>{const coordX=Math.max(this._eval(element.options.constraintXMin),Math.min(this._eval(element.options.constraintXMax),coord[0]));const coordY=Math.max(this._eval(element.options.constraintYMin),Math.min(this._eval(element.options.constraintYMax),coord[1]));return [coordX,coordY]}];if(element.options.constraint==="snap"){constraints.push(MovablePoint$2.constraints.snap(element.options.snap));}else if(element.options.constraint==="x"){constraints.push(coord=>{return [this._eval(element.options.constraintFn,{y:coord[1]}),coord[1]]});}else if(element.options.constraint==="y"){constraints.push(coord=>{return [coord[0],this._eval(element.options.constraintFn,{x:coord[0]})]});}const start=[this.state.variables["x_"+element.options.startSubscript],this.state.variables["y_"+element.options.startSubscript]];const end=[this.state.variables["x_"+element.options.endSubscript],this.state.variables["y_"+element.options.endSubscript]];return jsxRuntimeExports.jsxs(MovableLine$1,{constraints:constraints,onMove:___default.default.bind(this._updateLineLocation,this,element.options),foo_x:element.options.constraint,foo_y:element.options.constraintFn,foo_z:element.options.snap,children:[jsxRuntimeExports.jsx(MovablePoint$2,{coord:start,static:true,normalStyle:{stroke:"none",fill:"none"}}),jsxRuntimeExports.jsx(MovablePoint$2,{coord:end,static:true,normalStyle:{stroke:"none",fill:"none"}})]},element.key)}if(element.type==="function"){const fn=x=>{return this._eval(element.options.value,{x:x})};const vars=___default.default.without(this._extractVars(KASparse(element.options.value).expr),"x");const varValues=___default.default.object(vars,___default.default.map(vars,v=>this.state.variables[v]));const range=[this._eval(element.options.rangeMin,this.state.variables),this._eval(element.options.rangeMax,this.state.variables)];return jsxRuntimeExports.jsx(Plot,{fn:fn,foo_fn:element.options.value,foo_varvalues:varValues,range:range,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,plotPoints:100}},element.key)}if(element.type==="parametric"){const fn=t=>{return [this._eval(element.options.x,{t:t}),this._eval(element.options.y,{t:t})]};const vars=___default.default.without(this._extractVars(KASparse(element.options.x).expr).concat(this._extractVars(KASparse(element.options.y).expr)),"t");const varValues=___default.default.object(vars,___default.default.map(vars,v=>this.state.variables[v]));const range=[this._eval(element.options.rangeMin,this.state.variables),this._eval(element.options.rangeMax,this.state.variables)];return jsxRuntimeExports.jsx(PlotParametric,{fn:fn,foo_fnx:element.options.x,foo_fny:element.options.y,foo_varvalues:varValues,range:range,style:{stroke:element.options.color,strokeWidth:element.options.strokeWidth,strokeDasharray:element.options.strokeDasharray,plotPoints:100}},element.key)}if(element.type==="label"){const coord=[this._eval(element.options.coordX),this._eval(element.options.coordY)];return jsxRuntimeExports.jsx(Label,{coord:coord,text:unescapeMathMode(element.options.label),style:{color:element.options.color}},n+1)}if(element.type==="rectangle"){return jsxRuntimeExports.jsx(Rect,{x:this._eval(element.options.coordX),y:this._eval(element.options.coordY),width:___default.default.max([this._eval(element.options.width),0]),height:___default.default.max([this._eval(element.options.height),0]),style:{stroke:"none",fill:element.options.color}},n+1)}},this)]})}constructor(...args){super(...args),this.isWidget=true,this.state={variables:_getInitialVariables(this.props.elements),functions:_getInitialFunctions(this.props.elements)},this._setupGraphie=(graphie,options)=>{graphie.graphInit(___default.default.extend({},options,{grid:___default.default.contains(["graph","grid"],this.props.graph.markings),axes:___default.default.contains(["graph"],this.props.graph.markings),ticks:___default.default.contains(["graph"],this.props.graph.markings),labels:___default.default.contains(["graph"],this.props.graph.markings),labelFormat:function(s){return "\\small{"+s+"}"},axisArrows:"<->",unityLabels:false}));},this._updatePointLocation=(subscript,coord)=>{const variables=___default.default.clone(this.state.variables);variables["x_"+subscript]=coord[0];variables["y_"+subscript]=coord[1];this.setState({variables:variables});this.props.trackInteraction();},this._updateLineLocation=(options,startCoord)=>{const xDiff=this._eval("("+options.endX+")-("+options.startX+")");const yDiff=this._eval("("+options.endY+")-("+options.startY+")");const endCoord=kmath.vector.add(startCoord,[xDiff,yDiff]);const variables=___default.default.clone(this.state.variables);variables["x_"+options.startSubscript]=startCoord[0];variables["y_"+options.startSubscript]=startCoord[1];variables["x_"+options.endSubscript]=endCoord[0];variables["y_"+options.endSubscript]=endCoord[1];this.setState({variables:variables});this.props.trackInteraction();},this._eval=(expression,variables)=>{const func=KAScompile(expression,{functions:this.state.functions});const compiledVars=___default.default.extend({},this.state.variables,variables);___default.default.each(___default.default.keys(compiledVars),name=>{if(___default.default.isString(compiledVars[name])){const func=KAScompile(compiledVars[name],{functions:this.state.functions});compiledVars[name]=function(x){return func(___default.default.extend({},compiledVars,{x:x}))};}});return func(compiledVars)||0},this._extractVars=expr=>{if(expr==null){return []}let vars=[];___default.default.each(expr.args(),function(arg){if(arg&&arg.constructor.name==="Expr"){vars=vars.concat(this._extractVars(arg));}},this);if(expr.name()==="Var"){vars.push(expr.prettyPrint());}return vars};}}Interaction.defaultProps={graph:{box:[400,400],labels:["x","y"],range:[[-10,10],[-10,10]],tickStep:[1,1],gridStep:[1,1],markings:"graph"},elements:[]};const _getInitialVariables=elements=>{const variables={};___default.default.each(___default.default.where(elements,{type:"movable-point"}),element=>{const subscript=element.options.varSubscript;const startXExpr=KASparse(element.options.startX||"0").expr;const startYExpr=KASparse(element.options.startY||"0").expr;let startX=0;let startY=0;if(startXExpr){startX=startXExpr.eval({})||0;}if(startYExpr){startY=startYExpr.eval({})||0;}variables["x_"+subscript]=startX;variables["y_"+subscript]=startY;});___default.default.each(___default.default.where(elements,{type:"movable-line"}),element=>{const startSubscript=element.options.startSubscript;const endSubscript=element.options.endSubscript;const startXExpr=KASparse(element.options.startX||"0").expr;const startYExpr=KASparse(element.options.startY||"0").expr;const endXExpr=KASparse(element.options.endX||"0").expr;const endYExpr=KASparse(element.options.endY||"0").expr;let startX=0;let startY=0;let endX=0;let endY=0;if(startXExpr){startX=startXExpr.eval({})||0;}if(startYExpr){startY=startYExpr.eval({})||0;}if(endXExpr){endX=endXExpr.eval({})||0;}if(endYExpr){endY=endYExpr.eval({})||0;}variables["x_"+startSubscript]=startX;variables["y_"+startSubscript]=startY;variables["x_"+endSubscript]=endX;variables["y_"+endSubscript]=endY;});___default.default.each(___default.default.where(elements,{type:"function"}),element=>{variables[element.options.funcName]=element.options.value;});return variables};const _getInitialFunctions=elements=>{return ___default.default.map(___default.default.where(elements,{type:"function"}),element=>element.options.funcName)};var Interactive = {name:"interaction",displayName:"Interaction",widget:Interaction,hidden:true};
1910
1910
 
1911
1911
  const getPromptJSON$b=(props,userInput)=>{return {type:"interactive-graph",options:{graph:getGraphOptionsForProps(props),backgroundImageUrl:props.backgroundImage?.url,range:props.range,labels:props.labels},userInput:getUserInput(userInput)}};const getGraphOptionsForProps=props=>{const type=props.userInput.type;switch(type){case "angle":return {type:props.userInput.type,angleOffsetDegrees:props.userInput.angleOffsetDeg,startCoords:props.userInput.startCoords};case "circle":return {type:props.userInput.type,startParams:{center:props.userInput.startCoords?.center,radius:props.userInput.startCoords?.radius}};case "linear":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "linear-system":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "point":return {type:props.userInput.type,numPoints:props.userInput.numPoints,startCoords:props.userInput.startCoords};case "polygon":return {type:props.userInput.type,match:props.userInput.match,numSides:props.userInput.numSides,startCoords:props.userInput.startCoords};case "quadratic":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "ray":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "segment":return {type:props.userInput.type,numSegments:props.userInput.numSegments,startCoords:props.userInput.startCoords};case "sinusoid":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "tangent":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "none":return {};case "absolute-value":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "exponential":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "logarithm":return {type:props.userInput.type,startCoords:props.userInput.startCoords};case "vector":return {type:props.userInput.type,startCoords:props.userInput.startCoords};default:throw new wonderStuffCore.UnreachableCaseError(type)}};const getUserInput=userInput=>{const type=userInput.type;switch(type){case "angle":return {coords:userInput.coords,angleOffsetDegrees:userInput.angleOffsetDeg};case "circle":return {center:userInput.center,radius:userInput.radius};case "linear":return {coords:userInput.coords};case "linear-system":return {coords:userInput.coords};case "point":return {coords:userInput.coords};case "polygon":return {coords:userInput.coords};case "quadratic":return {coords:userInput.coords};case "ray":return {coords:userInput.coords};case "segment":return {coords:userInput.coords};case "sinusoid":return {coords:userInput.coords};case "tangent":return {coords:userInput.coords};case "none":return {};case "absolute-value":return {coords:userInput.coords};case "exponential":return {coords:userInput.coords,asymptote:userInput.asymptote};case "logarithm":return {coords:userInput.coords,asymptote:userInput.asymptote};case "vector":return {coords:userInput.coords};default:throw new wonderStuffCore.UnreachableCaseError(type)}};
1912
1912
 
@@ -1946,13 +1946,13 @@ function Hairlines(props){const{point}=props;const{range}=useGraphConfig();const
1946
1946
 
1947
1947
  const hitboxSizePx$1=48;const MovablePointView=React.forwardRef(function MovablePointViewWithRef(props,hitboxRef){const{markings,showTooltips,interactiveColor,disableKeyboardInteraction,snapStep}=useGraphConfig();const{point,dragging,focused,cursor,showFocusRing,onClick=()=>{}}=props;const wbColorName=disableKeyboardInteraction?"fadedOffBlack64":"blue";const pointClasses=classNames$1("movable-point",dragging&&"movable-point--dragging",showFocusRing&&"movable-point--focus");const[[x,y]]=useTransformVectorsToPixels(point);const showHairlines=(dragging||focused)&&markings!=="none";const xSigFigs=countSignificantDecimals(snapStep[X]);const ySigFigs=countSignificantDecimals(snapStep[Y]);const xTickLabel=point[X].toFixed(xSigFigs);const yTickLabel=point[Y].toFixed(ySigFigs);const pointTooltipContent=`(${xTickLabel}, ${yTickLabel})`;const svgForPoint=jsxRuntimeExports.jsxs("g",{"aria-hidden":true,ref:hitboxRef,className:pointClasses,style:{"--movable-point-color":interactiveColor,cursor},"data-testid":"movable-point",onClick:onClick,children:[jsxRuntimeExports.jsx("circle",{className:"movable-point-hitbox",r:hitboxSizePx$1/2,cx:x,cy:y}),jsxRuntimeExports.jsx("circle",{className:"movable-point-halo",cx:x,cy:y}),jsxRuntimeExports.jsx("circle",{className:"movable-point-ring",cx:x,cy:y}),jsxRuntimeExports.jsx("circle",{className:"movable-point-focus-outline",cx:x,cy:y}),jsxRuntimeExports.jsx("circle",{className:"movable-point-center",cx:x,cy:y,style:{fill:interactiveColor},"data-testid":"movable-point__center"})]});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showHairlines&&jsxRuntimeExports.jsx(Hairlines,{point:point}),showTooltips?jsxRuntimeExports.jsx(Tooltip__default.default,{autoUpdate:true,opened:true,backgroundColor:wbColorName,content:pointTooltipContent,contentStyle:{color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default},children:svgForPoint}):svgForPoint]})});function classNames$1(...names){return names.filter(Boolean).join(" ")}
1948
1948
 
1949
- function useControlPoint(params){const{snapStep,disableKeyboardInteraction}=useGraphConfig();const{point,ariaDescribedBy,ariaLabel,ariaLive="polite",constrain=p=>snap(snapStep,p),cursor,forwardedRef=noop$1,sequenceNumber=1,onMove=noop$1,onDragStart=noop$1,onDragEnd=noop$1,onClick=noop$1,onFocus=noop$1,onBlur=noop$1}=params;const{strings,locale}=usePerseusI18n();const[focused,setFocused]=React.useState(false);const focusableHandleRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const visiblePointRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:visiblePointRef,point,onMove,onDragStart,onDragEnd,constrainKeyboardMovement:constrain});const pointAriaLabel=ariaLabel||strings.srPointAtCoordinates({num:sequenceNumber,x:srFormatNumber(point[X],locale),y:srFormatNumber(point[Y],locale)});React.useLayoutEffect(()=>{setForwardedRef(forwardedRef,focusableHandleRef.current);},[forwardedRef]);React.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const focusableHandle=jsxRuntimeExports.jsx("g",{"data-testid":"movable-point__focusable-handle",className:"movable-point__focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,ref:focusableHandleRef,role:"button","aria-describedby":ariaDescribedBy,"aria-label":pointAriaLabel,"aria-live":ariaLive,"aria-disabled":disableKeyboardInteraction,onFocus:event=>{onFocus(event);setFocused(true);},onBlur:event=>{onBlur(event);setFocused(false);}});const visiblePoint=jsxRuntimeExports.jsx(MovablePointView,{cursor:cursor,onClick:()=>{onClick();focusableHandleRef.current?.focus();},point:point,dragging:dragging,focused:focused,ref:visiblePointRef,showFocusRing:focused});return {focusableHandle,visiblePoint,focusableHandleRef,visiblePointRef}}function setForwardedRef(ref,value){if(typeof ref==="function"){ref(value);}else if(ref!==null){ref.current=value;}}const noop$1=()=>{};
1949
+ function useControlPoint(params){const{snapStep,disableKeyboardInteraction}=useGraphConfig();const{point,ariaDescribedBy,ariaLabel,constrain=p=>snap(snapStep,p),cursor,forwardedRef=noop$1,sequenceNumber=1,onMove=noop$1,onDragStart=noop$1,onDragEnd=noop$1,onClick=noop$1,onFocus=noop$1,onBlur=noop$1}=params;const{strings,locale}=usePerseusI18n();const[focused,setFocused]=React.useState(false);const focusableHandleRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const visiblePointRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:visiblePointRef,point,onMove,onDragStart,onDragEnd,constrainKeyboardMovement:constrain});const pointAriaLabel=ariaLabel||strings.srPointAtCoordinates({num:sequenceNumber,x:srFormatNumber(point[X],locale),y:srFormatNumber(point[Y],locale)});React.useLayoutEffect(()=>{setForwardedRef(forwardedRef,focusableHandleRef.current);},[forwardedRef]);React.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const focusableHandle=jsxRuntimeExports.jsx("g",{"data-testid":"movable-point__focusable-handle",className:"movable-point__focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,ref:focusableHandleRef,role:"button","aria-describedby":ariaDescribedBy,"aria-label":pointAriaLabel,"aria-disabled":disableKeyboardInteraction,onFocus:event=>{onFocus(event);setFocused(true);},onBlur:event=>{onBlur(event);setFocused(false);}});const visiblePoint=jsxRuntimeExports.jsx(MovablePointView,{cursor:cursor,onClick:()=>{onClick();focusableHandleRef.current?.focus();},point:point,dragging:dragging,focused:focused,ref:visiblePointRef,showFocusRing:focused});return {focusableHandle,visiblePoint,focusableHandleRef,visiblePointRef}}function setForwardedRef(ref,value){if(typeof ref==="function"){ref(value);}else if(ref!==null){ref.current=value;}}const noop$1=()=>{};
1950
1950
 
1951
1951
  const MovablePoint$1=React__namespace.forwardRef(function MovablePointWithRef(props,pointRef){const{visiblePoint,focusableHandle}=useControlPoint({...props,forwardedRef:pointRef});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[focusableHandle,visiblePoint]})});
1952
1952
 
1953
1953
  function SRDescInSVG(props){const{id,children}=props;return jsxRuntimeExports.jsx("foreignObject",{children:jsxRuntimeExports.jsx("span",{id:id,style:a11y.srOnly,"aria-hidden":true,children:children})})}
1954
1954
 
1955
- function renderAbsoluteValueGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(AbsoluteValueGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getAbsoluteValueDescription(state,i18n)}}function AbsoluteValueGraph(props){const{dispatch,graphState}=props;const{interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({m:1,h:0,v:0});const coeffs=getAbsoluteValueCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const{m,h,v}=coeffRef.current;const{srAbsoluteValueGraph,srAbsoluteValueVertexPoint,srAbsoluteValueSecondPoint,srAbsoluteValueDescription:srDescription}=describeAbsoluteValueGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srAbsoluteValueGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>m*Math.abs(x-h)+v,color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srAbsoluteValueVertexPoint:srAbsoluteValueSecondPoint),point:coord,sequenceNumber:i+1,constrain:getAbsoluteValueKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.absoluteValue.movePoint(i,destination)),ariaLive:"off"},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srDescription})]})}function getAbsoluteValueCoefficients(coords){const p1=coords[0];const p2=coords[1];const denom=p2[X]-p1[X];if(denom===0){return undefined}const num=p2[Y]-p1[Y];let m=Math.abs(num/denom);if(p2[Y]<p1[Y]){m=-m;}return {m,h:p1[X],v:p1[Y]}}const getAbsoluteValueKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const moveWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:mafs.vec.add(coordToBeMoved,[0,snapStep[Y]]),down:mafs.vec.sub(coordToBeMoved,[0,snapStep[Y]]),left:moveWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[X],0])),right:moveWithConstraint(coord=>mafs.vec.add(coord,[snapStep[X],0]))}};function getAbsoluteValueDescription(state,i18n){const{strings}=i18n;const{coords}=state;const{locale}=i18n;const[p1,p2]=coords;return strings.srInteractiveElements({elements:strings.srAbsoluteValueInteractiveElements({point1X:srFormatNumber(p1[X],locale),point1Y:srFormatNumber(p1[Y],locale),point2X:srFormatNumber(p2[X],locale),point2Y:srFormatNumber(p2[Y],locale)})})}function describeAbsoluteValueGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[vertex,armPoint]=coords;const coeffs=getAbsoluteValueCoefficients(coords);const m=coeffs?.m??1;const srAbsoluteValueGraph=strings.srAbsoluteValueGraph;const srAbsoluteValueVertexPoint=strings.srAbsoluteValueVertexPoint({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale)});const srAbsoluteValueSecondPoint=strings.srAbsoluteValueSecondPoint({x:srFormatNumber(armPoint[X],locale),y:srFormatNumber(armPoint[Y],locale)});const srAbsoluteValueDescription=strings.srAbsoluteValueDescription({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale),slope:srFormatNumber(m,locale)});return {srAbsoluteValueGraph,srAbsoluteValueVertexPoint,srAbsoluteValueSecondPoint,srAbsoluteValueDescription}}
1955
+ function renderAbsoluteValueGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(AbsoluteValueGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getAbsoluteValueDescription(state,i18n)}}function AbsoluteValueGraph(props){const{dispatch,graphState}=props;const{interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({m:1,h:0,v:0});const coeffs=getAbsoluteValueCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const{m,h,v}=coeffRef.current;const{srAbsoluteValueGraph,srAbsoluteValueVertexPoint,srAbsoluteValueSecondPoint,srAbsoluteValueDescription:srDescription}=describeAbsoluteValueGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srAbsoluteValueGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>m*Math.abs(x-h)+v,color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srAbsoluteValueVertexPoint:srAbsoluteValueSecondPoint),point:coord,sequenceNumber:i+1,constrain:getAbsoluteValueKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.absoluteValue.movePoint(i,destination))},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srDescription})]})}function getAbsoluteValueCoefficients(coords){const p1=coords[0];const p2=coords[1];const denom=p2[X]-p1[X];if(denom===0){return undefined}const num=p2[Y]-p1[Y];let m=Math.abs(num/denom);if(p2[Y]<p1[Y]){m=-m;}return {m,h:p1[X],v:p1[Y]}}const getAbsoluteValueKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const moveWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:mafs.vec.add(coordToBeMoved,[0,snapStep[Y]]),down:mafs.vec.sub(coordToBeMoved,[0,snapStep[Y]]),left:moveWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[X],0])),right:moveWithConstraint(coord=>mafs.vec.add(coord,[snapStep[X],0]))}};function getAbsoluteValueDescription(state,i18n){const{strings}=i18n;const{coords}=state;const{locale}=i18n;const[p1,p2]=coords;return strings.srInteractiveElements({elements:strings.srAbsoluteValueInteractiveElements({point1X:srFormatNumber(p1[X],locale),point1Y:srFormatNumber(p1[Y],locale),point2X:srFormatNumber(p2[X],locale),point2Y:srFormatNumber(p2[Y],locale)})})}function describeAbsoluteValueGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[vertex,armPoint]=coords;const coeffs=getAbsoluteValueCoefficients(coords);const m=coeffs?.m??1;const srAbsoluteValueGraph=strings.srAbsoluteValueGraph;const srAbsoluteValueVertexPoint=strings.srAbsoluteValueVertexPoint({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale)});const srAbsoluteValueSecondPoint=strings.srAbsoluteValueSecondPoint({x:srFormatNumber(armPoint[X],locale),y:srFormatNumber(armPoint[Y],locale)});const srAbsoluteValueDescription=strings.srAbsoluteValueDescription({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale),slope:srFormatNumber(m,locale)});return {srAbsoluteValueGraph,srAbsoluteValueVertexPoint,srAbsoluteValueSecondPoint,srAbsoluteValueDescription}}
1956
1956
 
1957
1957
  const{getClockwiseAngle: getClockwiseAngle$2}=kmath.angles;const{getSinusoidCoefficients: getSinusoidCoefficients$1,getTangentCoefficients: getTangentCoefficients$1,getQuadraticCoefficients: getQuadraticCoefficients$2,getExponentialCoefficients: getExponentialCoefficients$1,getLogarithmCoefficients: getLogarithmCoefficients$1}=kmath.coefficients;const{getLineEquation,getLineIntersectionString,magnitude: magnitude$2,vector: vector$2}=kmath.geometry;const UNLIMITED="unlimited";function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}const makeInvalidTypeError=(functionName,graphType)=>{return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`,perseusCore.Errors.NotAllowed,{metadata:{graphType}})};function getLineCoords$1(graph,props){return graph.coords||pointsFromNormalized(props,[[.25,.75],[.75,.75]])}function getPointCoords$1(graph,props){const numPoints=graph.numPoints||1;let coords=graph.coords;if(coords){return coords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;case UNLIMITED:coords=[];break}const range=[[-10,10],[-10,10]];const newCoords=normalizeCoords(coords,range);return pointsFromNormalized(props,newCoords)}function getLinearSystemCoords$1(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return pointsFromNormalized(props,coords)})}function getPolygonCoords$1(graph,props){if(graph.type!=="polygon"){throw makeInvalidTypeError("toggleShowSides","polygon")}let coords=graph.coords;if(coords){return coords}const n=graph.numSides||3;if(n===UNLIMITED){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=___default.default.times(n,function(i){return [radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]});}const ranges=[[-10,10],[-10,10]];coords=normalizeCoords(coords,ranges);const snapToGrid=!___default.default.contains(["angles","sides"],graph.snapTo);coords=pointsFromNormalized(props,coords,!snapToGrid);return coords}function getSegmentCoords$1(graph,props){const coords=graph.coords;if(coords){return coords}const n=graph.numSegments||1;const ys={1:[5],2:[5,-5],3:[5,0,-5],4:[6,2,-2,-6],5:[6,3,0,-3,-6],6:[5,3,1,-1,-3,-5]}[n];const range=[[-10,10],[-10,10]];return ys.map(function(y){let segment=[[-5,y],[5,y]];segment=normalizeCoords(segment,range);segment=pointsFromNormalized(props,segment);return segment})}function getAngleCoords$1(graph,props){let coords=graph.coords;if(coords){return coords}const snap=graph.snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(graph.angleOffsetDeg||0)*Math.PI/180;coords=pointsFromNormalized(props,[[.85,.5],[.5,.5]]);const radius=magnitude$2(vector$2(...coords));coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords}function normalizeCoords(coordsList,ranges){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const extent=ranges[i][1]-ranges[i][0];return (coord+ranges[i][1])/extent})})}function pointsFromNormalized(props,coordsList,noSnap){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const range=props.range[i];if(noSnap){return range[0]+(range[1]-range[0])*coord}const step=props.step[i];const nSteps=numSteps(range,step);const tick=Math.round(coord*nSteps);return range[0]+step*tick})})}function getNoneEquationString(){return ""}function getLinearEquationString(props){const coords=getLineCoords$1(props.userInput,props);if(perseusCore.approximateEqual(coords[0][0],coords[1][0])){return "x = "+coords[0][0].toFixed(3)}const m=(coords[1][1]-coords[0][1])/(coords[1][0]-coords[0][0]);const b=coords[0][1]-m*coords[0][0];if(perseusCore.approximateEqual(m,0)){return "y = "+b.toFixed(3)}return "y = "+m.toFixed(3)+"x + "+b.toFixed(3)}function getCurrentQuadraticCoefficients(props){const coords=props.userInput.coords||defaultQuadraticCoords(props);return getQuadraticCoefficients$2(coords)}function defaultQuadraticCoords(props){const coords=[[.25,.75],[.5,.25],[.75,.75]];return pointsFromNormalized(props,coords)}function getQuadraticEquationString(props){const coeffs=getCurrentQuadraticCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"x^2 + "+coeffs[1].toFixed(3)+"x + "+coeffs[2].toFixed(3)}function getCurrentSinusoidCoefficients(props){const coords=props.userInput.coords||defaultSinusoidCoords(props);return getSinusoidCoefficients$1(coords)}function defaultSinusoidCoords(props){const coords=[[.5,.5],[.65,.6]];return pointsFromNormalized(props,coords)}function getSinusoidEquationString(props){const coeffs=getCurrentSinusoidCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"sin("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}function defaultExponentialCoords(props){const coords=[[.5,.55],[.75,.75]];return pointsFromNormalized(props,coords,true)}function getExponentialEquationString(props){const coords=props.userInput.coords||defaultExponentialCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getExponentialCoefficients$1(coords,asymptote);if(coeffs==null){return "y = e^x"}return "y = "+coeffs.a.toFixed(3)+"e^("+coeffs.b.toFixed(3)+"x) + "+coeffs.c.toFixed(3)}function defaultLogarithmCoords(props){const coords=[[.55,.55],[.75,.75]];return pointsFromNormalized(props,coords,true)}function getLogarithmEquationString(props){const coords=props.userInput.coords||defaultLogarithmCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getLogarithmCoefficients$1(coords,asymptote);if(coeffs==null){return "y = ln(x)"}const cStr=coeffs.c===0?"x":coeffs.c<0?"x - "+Math.abs(coeffs.c).toFixed(3):"x + "+coeffs.c.toFixed(3);return "y = "+coeffs.a.toFixed(3)+"ln("+coeffs.b.toFixed(3)+cStr+")"}function getAbsoluteValueEquationString(props){const userInput=props.userInput;if(userInput.type!=="absolute-value"||!userInput.coords){return ""}const coeffs=getAbsoluteValueCoefficients(userInput.coords);if(coeffs===undefined){return ""}const{m,h,v}=coeffs;return "y = "+m.toFixed(3)+"|x - "+h.toFixed(3)+"| + "+v.toFixed(3)}function getCurrentTangentCoefficients(props){const coords=props.userInput.coords||defaultTangentCoords(props);return getTangentCoefficients$1(coords)}function defaultTangentCoords(props){const coords=[[.5,.5],[.75,.75]];return pointsFromNormalized(props,coords)}function getTangentEquationString(props){const coeffs=getCurrentTangentCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"tan("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}function getCircleEquationString(props){const graph=props.userInput;const center=graph.center||[0,0];const radius=graph.radius||2;return "center ("+center[0]+", "+center[1]+"), radius "+radius}function getLinearSystemEquationString(props){const coords=getLinearSystemCoords$1(props.userInput,props);return "\n"+getLineEquation(coords[0][0],coords[0][1])+"\n"+getLineEquation(coords[1][0],coords[1][1])+"\n"+getLineIntersectionString(coords[0],coords[1])}function getPointEquationString(props){if(props.userInput.type!=="point"){throw makeInvalidTypeError("getPointEquationString","point")}const coords=getPointCoords$1(props.userInput,props);return coords.map(function(coord){return "("+coord[0]+", "+coord[1]+")"}).join(", ")}function getSegmentEquationString(props){if(props.userInput.type!=="segment"){throw makeInvalidTypeError("getSegmentEquationString","segment")}const segments=getSegmentCoords$1(props.userInput,props);return ___default.default.map(segments,function(segment){return "["+___default.default.map(segment,function(coord){return "("+coord.join(", ")+")"}).join(" ")+"]"}).join(" ")}function getRayEquationString(props){if(props.userInput.type!=="ray"){throw makeInvalidTypeError("createPointForPolygonType","ray")}const coords=getLineCoords$1(props.userInput,props);const a=coords[0];const b=coords[1];let eq=getLinearEquationString(props);if(a[0]>b[0]){eq+=" (for x <= "+a[0].toFixed(3)+")";}else if(a[0]<b[0]){eq+=" (for x >= "+a[0].toFixed(3)+")";}else if(a[1]>b[1]){eq+=" (for y <= "+a[1].toFixed(3)+")";}else {eq+=" (for y >= "+a[1].toFixed(3)+")";}return eq}function getPolygonEquationString(props){if(props.userInput.type!=="polygon"){throw makeInvalidTypeError("getPolygonEquationString","polygon")}const coords=getPolygonCoords$1(props.userInput,props);return ___default.default.map(coords,function(coord){return "("+coord.join(", ")+")"}).join(" ")}function getAngleEquationString(props){if(props.userInput.type!=="angle"){throw makeInvalidTypeError("getAngleEquationString","angle")}const coords=getAngleCoords$1(props.userInput,props);const allowReflexAngles=props.userInput.allowReflexAngles;const angle=getClockwiseAngle$2(coords,allowReflexAngles);return angle.toFixed(0)+"° angle"+" at ("+coords[1].join(", ")+")"}function getVectorEquationString(props){if(props.userInput.type!=="vector"){throw makeInvalidTypeError("getVectorEquationString","vector")}const coords=props.userInput.coords;if(!coords){return ""}const[tail,tip]=coords;const dx=tip[0]-tail[0];const dy=tip[1]-tail[1];return `\u27E8${dx.toFixed(3)}, ${dy.toFixed(3)}\u27E9`}function getEquationString(props){const type=props.userInput.type;switch(type){case "none":return getNoneEquationString();case "linear":return getLinearEquationString(props);case "quadratic":return getQuadraticEquationString(props);case "sinusoid":return getSinusoidEquationString(props);case "circle":return getCircleEquationString(props);case "linear-system":return getLinearSystemEquationString(props);case "point":return getPointEquationString(props);case "segment":return getSegmentEquationString(props);case "ray":return getRayEquationString(props);case "polygon":return getPolygonEquationString(props);case "angle":return getAngleEquationString(props);case "absolute-value":return getAbsoluteValueEquationString(props);case "exponential":return getExponentialEquationString(props);case "tangent":return getTangentEquationString(props);case "logarithm":return getLogarithmEquationString(props);case "vector":return getVectorEquationString(props);default:throw new wonderStuffCore.UnreachableCaseError(type)}}
1958
1958
 
@@ -2004,11 +2004,11 @@ const{clockwise: clockwise$1}=kmath.geometry;const{getAngleFromVertex: getAngleF
2004
2004
 
2005
2005
  const getMovableLineKeyboardConstraint=(line,snapStep,pointIndex)=>{const coordToBeMoved=line[pointIndex];const otherPoint=line[1-pointIndex];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(mafs.vec.dist(movedCoord,otherPoint)===0){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[1]])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[1]])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const GRAPH_EDGE_INSET_PX=4;function trimRange(range,graphDimensionsInPixels){const[xRange,yRange]=range;const[pixelsWide,pixelsTall]=graphDimensionsInPixels;const graphUnitsPerPixelX=size(xRange)/pixelsWide;const graphUnitsPerPixelY=size(yRange)/pixelsTall;const graphUnitsToTrimX=GRAPH_EDGE_INSET_PX*graphUnitsPerPixelX;const graphUnitsToTrimY=GRAPH_EDGE_INSET_PX*graphUnitsPerPixelY;return inset([graphUnitsToTrimX,graphUnitsToTrimY],range)}function insetTipAlongRay(tail,tip,range,graphDimensionsInPixels){const dx=tip[0]-tail[0];const dy=tip[1]-tail[1];const[pixelsWide,pixelsTall]=graphDimensionsInPixels;const pxPerUnitX=pixelsWide/size(range[0]);const pxPerUnitY=pixelsTall/size(range[1]);const lenPx=Math.hypot(dx*pxPerUnitX,dy*pxPerUnitY);if(lenPx===0){return tip}const scale=GRAPH_EDGE_INSET_PX/lenPx;return [tip[0]-dx*scale,tip[1]-dy*scale]}
2006
2006
 
2007
- const Line$1=props=>{const{start,end,ariaLabel,ariaDescribedBy,ariaLive,extend,onMove}=props;const[startPtPx,endPtPx]=useTransformVectorsToPixels(start,end);const{range,graphDimensionsInPixels,snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const computeExtensionTip=(tail,source)=>insetTipAlongRay(tail,getIntersectionOfRayWithBox(source,tail,range),range,graphDimensionsInPixels);const startExtend=extend?.start?computeExtensionTip(start,end):undefined;const endExtend=extend?.end?computeExtensionTip(end,start):undefined;const line=React.useRef(null);const{dragging}=useDraggable({gestureTarget:line,point:start,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("g",{ref:line,tabIndex:disableKeyboardInteraction?-1:0,"aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-live":ariaLive,"aria-disabled":disableKeyboardInteraction,className:"movable-line","data-testid":"movable-line",style:{cursor:dragging?"grabbing":"grab"},role:"button",children:[jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,className:"movable-line-focus-outline",style:{}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,className:"movable-line-focus-outline-gap",style:{}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:interactiveColor,strokeWidth:"var(--movable-line-stroke-weight)"},className:dragging?"movable-dragging":"",testId:"movable-line__line"})]}),startExtend&&jsxRuntimeExports.jsx(Vector,{tail:start,tip:startExtend,testId:"movable-line__vector"}),endExtend&&jsxRuntimeExports.jsx(Vector,{tail:end,tip:endExtend,testId:"movable-line__vector"})]})};
2007
+ const Line$1=props=>{const{start,end,ariaLabel,ariaDescribedBy,extend,onMove}=props;const[startPtPx,endPtPx]=useTransformVectorsToPixels(start,end);const{range,graphDimensionsInPixels,snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const computeExtensionTip=(tail,source)=>insetTipAlongRay(tail,getIntersectionOfRayWithBox(source,tail,range),range,graphDimensionsInPixels);const startExtend=extend?.start?computeExtensionTip(start,end):undefined;const endExtend=extend?.end?computeExtensionTip(end,start):undefined;const line=React.useRef(null);const{dragging}=useDraggable({gestureTarget:line,point:start,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("g",{ref:line,tabIndex:disableKeyboardInteraction?-1:0,"aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-disabled":disableKeyboardInteraction,className:"movable-line","data-testid":"movable-line",style:{cursor:dragging?"grabbing":"grab"},role:"button",children:[jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,className:"movable-line-focus-outline",style:{}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,className:"movable-line-focus-outline-gap",style:{}}),jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:interactiveColor,strokeWidth:"var(--movable-line-stroke-weight)"},className:dragging?"movable-dragging":"",testId:"movable-line__line"})]}),startExtend&&jsxRuntimeExports.jsx(Vector,{tail:start,tip:startExtend,testId:"movable-line__vector"}),endExtend&&jsxRuntimeExports.jsx(Vector,{tail:end,tip:endExtend,testId:"movable-line__vector"})]})};
2008
2008
 
2009
- const MovableLine=props=>{const{points:[start,end],ariaLabels,ariaDescribedBy,ariaLive,extend,onMoveLine=()=>{},onMovePoint=()=>{}}=props;const{snapStep}=useGraphConfig();const[ariaLives,setAriaLives]=React__namespace.useState(["off","off","off"]);const point1AriaLive=ariaLive??ariaLives[0];const point2AriaLive=ariaLive??ariaLives[1];const lineAriaLive=ariaLive??ariaLives[2];const{visiblePoint:visiblePoint1,focusableHandle:focusableHandle1}=useControlPoint({ariaLabel:ariaLabels?.point1AriaLabel,ariaDescribedBy:ariaDescribedBy,ariaLive:point1AriaLive,point:start,sequenceNumber:1,onMove:p=>{setAriaLives(["polite","off","off"]);onMovePoint(0,p);},constrain:getMovableLineKeyboardConstraint([start,end],snapStep,0)});const{visiblePoint:visiblePoint2,focusableHandle:focusableHandle2}=useControlPoint({ariaLabel:ariaLabels?.point2AriaLabel,ariaDescribedBy:ariaDescribedBy,ariaLive:point2AriaLive,point:end,sequenceNumber:2,onMove:p=>{setAriaLives(["off","polite","off"]);onMovePoint(1,p);},constrain:getMovableLineKeyboardConstraint([start,end],snapStep,1)});const line=jsxRuntimeExports.jsx(Line$1,{ariaLabel:ariaLabels?.grabHandleAriaLabel,ariaDescribedBy:ariaDescribedBy,ariaLive:lineAriaLive,start:start,end:end,extend:extend,onMove:newStart=>{setAriaLives(["off","off","polite"]);onMoveLine(newStart);}});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[focusableHandle1,line,focusableHandle2,visiblePoint1,visiblePoint2]})};
2009
+ const MovableLine=props=>{const{points:[start,end],ariaLabels,ariaDescribedBy,extend,onMoveLine=()=>{},onMovePoint=()=>{}}=props;const{snapStep}=useGraphConfig();const{visiblePoint:visiblePoint1,focusableHandle:focusableHandle1}=useControlPoint({ariaLabel:ariaLabels?.point1AriaLabel,ariaDescribedBy:ariaDescribedBy,point:start,sequenceNumber:1,onMove:p=>{onMovePoint(0,p);},constrain:getMovableLineKeyboardConstraint([start,end],snapStep,0)});const{visiblePoint:visiblePoint2,focusableHandle:focusableHandle2}=useControlPoint({ariaLabel:ariaLabels?.point2AriaLabel,ariaDescribedBy:ariaDescribedBy,point:end,sequenceNumber:2,onMove:p=>{onMovePoint(1,p);},constrain:getMovableLineKeyboardConstraint([start,end],snapStep,1)});const line=jsxRuntimeExports.jsx(Line$1,{ariaLabel:ariaLabels?.grabHandleAriaLabel,ariaDescribedBy:ariaDescribedBy,start:start,end:end,extend:extend,onMove:newStart=>{onMoveLine(newStart);}});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[focusableHandle1,line,focusableHandle2,visiblePoint1,visiblePoint2]})};
2010
2010
 
2011
- const{calculateAngleInDegrees: calculateAngleInDegrees$2,getClockwiseAngle: getClockwiseAngle$1,polar: polar$1}=kmath.angles;function renderAngleGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(AngleGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getAngleGraphDescription(state,i18n)}}function AngleGraph(props){const{dispatch,graphState}=props;const{graphDimensionsInPixels,interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,showAngles,range,allowReflexAngles,snapDegrees}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const endPoints=[coords[0],coords[2]];const centerPoint=coords[1];const angleLines=[[centerPoint,endPoints[0]],[centerPoint,endPoints[1]]];const linePixelCoords=[useTransformVectorsToPixels(centerPoint,endPoints[0]),useTransformVectorsToPixels(centerPoint,endPoints[1])];const svgLines=linePixelCoords.map(([startPtPx,endPtPx],i)=>{const trimmedRange=trimRange(range,graphDimensionsInPixels);const endExtend=getIntersectionOfRayWithBox(angleLines[i][0],angleLines[i][1],trimmedRange);return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:interactiveColor,strokeWidth:"var(--movable-line-stroke-weight)"},testId:"angle-graph__line"}),jsxRuntimeExports.jsx(Vector,{tail:angleLines[i][1],tip:endExtend,testId:"angle-graph__vector"})]},`line-${i}`)});const angleParams={vertex:centerPoint,coords:endPoints,allowReflexAngles:allowReflexAngles||false,snapDegrees:snapDegrees||1,range:range,showAngles:showAngles||false};const{srAngleGraphAriaLabel,srAngleGraphAriaDescription,srAngleStartingSide,srAngleEndingSide,srAngleVertex}=describeAngleGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srAngleGraphAriaLabel,"aria-describedby":descriptionId,children:[svgLines,jsxRuntimeExports.jsx(Angle,{...angleParams}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[1],sequenceNumber:1,constrain:p=>p,onMove:destination=>dispatch(actions.angle.movePoint(1,destination)),ariaLabel:buildLabel(1,coords[1])??srAngleVertex,ariaLive:"off"}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[0],sequenceNumber:2,constrain:getAngleSideConstraint(coords[0],coords[1],snapDegrees||1),onMove:destination=>dispatch(actions.angle.movePoint(0,destination)),ariaLabel:buildLabel(0,coords[0])??srAngleEndingSide,ariaLive:"off"}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[2],sequenceNumber:3,constrain:getAngleSideConstraint(coords[2],coords[1],snapDegrees||1),onMove:destination=>dispatch(actions.angle.movePoint(2,destination)),ariaLabel:buildLabel(2,coords[2])??srAngleStartingSide,ariaLive:"off"}),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srAngleGraphAriaDescription})]})}function getAngleGraphDescription(state,i18n){const{strings,locale}=i18n;const{coords}=state;return strings.srInteractiveElements({elements:strings.srAngleInteractiveElements({vertexX:srFormatNumber(coords[1][X],locale),vertexY:srFormatNumber(coords[1][Y],locale),startingSideX:srFormatNumber(coords[2][X],locale),startingSideY:srFormatNumber(coords[2][Y],locale),endingSideX:srFormatNumber(coords[0][X],locale),endingSideY:srFormatNumber(coords[0][Y],locale)})})}function describeAngleGraph(state,i18n){const{strings,locale}=i18n;const{coords,allowReflexAngles}=state;const[endingSide,vertex,startingSide]=coords;const angleMeasure=srFormatNumber(getClockwiseAngle$1(coords,allowReflexAngles),locale);const srAngleGraphAriaLabel=strings.srAngleGraphAriaLabel;const srAngleGraphAriaDescription=strings.srAngleGraphAriaDescription({angleMeasure,vertexX:srFormatNumber(vertex[X],locale),vertexY:srFormatNumber(vertex[Y],locale),startingSideX:srFormatNumber(startingSide[X],locale),startingSideY:srFormatNumber(startingSide[Y],locale),endingSideX:srFormatNumber(endingSide[X],locale),endingSideY:srFormatNumber(endingSide[Y],locale)});const srAngleStartingSide=strings.srAngleStartingSide({x:srFormatNumber(startingSide[X],locale),y:srFormatNumber(startingSide[Y],locale)});const srAngleEndingSide=strings.srAngleEndingSide({x:srFormatNumber(endingSide[X],locale),y:srFormatNumber(endingSide[Y],locale)});const srAngleVertex=strings.srAngleVertexWithAngleMeasure({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale),angleMeasure});return {srAngleGraphAriaLabel,srAngleGraphAriaDescription,srAngleStartingSide,srAngleEndingSide,srAngleVertex}}const positiveX=[1,0];const negativeX=[-1,0];const positiveY=[0,1];const negativeY=[0,-1];function getAngleSideConstraint(sidePoint,vertex,snapDegrees){const currentAngle=calculateAngleInDegrees$2(mafs.vec.sub(sidePoint,vertex));const leftRay=[sidePoint,mafs.vec.add(sidePoint,negativeX)];const rightRay=[sidePoint,mafs.vec.add(sidePoint,positiveX)];const upRay=[sidePoint,mafs.vec.add(sidePoint,positiveY)];const downRay=[sidePoint,mafs.vec.add(sidePoint,negativeY)];const oneStepCounterClockwise=currentAngle+snapDegrees;const oneStepClockwise=currentAngle-snapDegrees;const counterClockwiseRay=[vertex,mafs.vec.add(vertex,polar$1(1,oneStepCounterClockwise))];const clockwiseRay=[vertex,mafs.vec.add(vertex,polar$1(1,oneStepClockwise))];const left=findIntersectionOfRays(leftRay,counterClockwiseRay)??findIntersectionOfRays(leftRay,clockwiseRay);const right=findIntersectionOfRays(rightRay,counterClockwiseRay)??findIntersectionOfRays(rightRay,clockwiseRay);const up=findIntersectionOfRays(upRay,counterClockwiseRay)??findIntersectionOfRays(upRay,clockwiseRay);const down=findIntersectionOfRays(downRay,counterClockwiseRay)??findIntersectionOfRays(downRay,clockwiseRay);return {up:up??sidePoint,down:down??sidePoint,left:left??sidePoint,right:right??sidePoint}}
2011
+ const{calculateAngleInDegrees: calculateAngleInDegrees$2,getClockwiseAngle: getClockwiseAngle$1,polar: polar$1}=kmath.angles;function renderAngleGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(AngleGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getAngleGraphDescription(state,i18n)}}function AngleGraph(props){const{dispatch,graphState}=props;const{graphDimensionsInPixels,interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,showAngles,range,allowReflexAngles,snapDegrees}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const endPoints=[coords[0],coords[2]];const centerPoint=coords[1];const angleLines=[[centerPoint,endPoints[0]],[centerPoint,endPoints[1]]];const linePixelCoords=[useTransformVectorsToPixels(centerPoint,endPoints[0]),useTransformVectorsToPixels(centerPoint,endPoints[1])];const svgLines=linePixelCoords.map(([startPtPx,endPtPx],i)=>{const trimmedRange=trimRange(range,graphDimensionsInPixels);const endExtend=getIntersectionOfRayWithBox(angleLines[i][0],angleLines[i][1],trimmedRange);return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(SVGLine,{start:startPtPx,end:endPtPx,style:{stroke:interactiveColor,strokeWidth:"var(--movable-line-stroke-weight)"},testId:"angle-graph__line"}),jsxRuntimeExports.jsx(Vector,{tail:angleLines[i][1],tip:endExtend,testId:"angle-graph__vector"})]},`line-${i}`)});const angleParams={vertex:centerPoint,coords:endPoints,allowReflexAngles:allowReflexAngles||false,snapDegrees:snapDegrees||1,range:range,showAngles:showAngles||false};const{srAngleGraphAriaLabel,srAngleGraphAriaDescription,srAngleStartingSide,srAngleEndingSide,srAngleVertex}=describeAngleGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srAngleGraphAriaLabel,"aria-describedby":descriptionId,children:[svgLines,jsxRuntimeExports.jsx(Angle,{...angleParams}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[1],sequenceNumber:1,constrain:p=>p,onMove:destination=>dispatch(actions.angle.movePoint(1,destination)),ariaLabel:buildLabel(1,coords[1])??srAngleVertex}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[0],sequenceNumber:2,constrain:getAngleSideConstraint(coords[0],coords[1],snapDegrees||1),onMove:destination=>dispatch(actions.angle.movePoint(0,destination)),ariaLabel:buildLabel(0,coords[0])??srAngleEndingSide}),jsxRuntimeExports.jsx(MovablePoint$1,{point:coords[2],sequenceNumber:3,constrain:getAngleSideConstraint(coords[2],coords[1],snapDegrees||1),onMove:destination=>dispatch(actions.angle.movePoint(2,destination)),ariaLabel:buildLabel(2,coords[2])??srAngleStartingSide}),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srAngleGraphAriaDescription})]})}function getAngleGraphDescription(state,i18n){const{strings,locale}=i18n;const{coords}=state;return strings.srInteractiveElements({elements:strings.srAngleInteractiveElements({vertexX:srFormatNumber(coords[1][X],locale),vertexY:srFormatNumber(coords[1][Y],locale),startingSideX:srFormatNumber(coords[2][X],locale),startingSideY:srFormatNumber(coords[2][Y],locale),endingSideX:srFormatNumber(coords[0][X],locale),endingSideY:srFormatNumber(coords[0][Y],locale)})})}function describeAngleGraph(state,i18n){const{strings,locale}=i18n;const{coords,allowReflexAngles}=state;const[endingSide,vertex,startingSide]=coords;const angleMeasure=srFormatNumber(getClockwiseAngle$1(coords,allowReflexAngles),locale);const srAngleGraphAriaLabel=strings.srAngleGraphAriaLabel;const srAngleGraphAriaDescription=strings.srAngleGraphAriaDescription({angleMeasure,vertexX:srFormatNumber(vertex[X],locale),vertexY:srFormatNumber(vertex[Y],locale),startingSideX:srFormatNumber(startingSide[X],locale),startingSideY:srFormatNumber(startingSide[Y],locale),endingSideX:srFormatNumber(endingSide[X],locale),endingSideY:srFormatNumber(endingSide[Y],locale)});const srAngleStartingSide=strings.srAngleStartingSide({x:srFormatNumber(startingSide[X],locale),y:srFormatNumber(startingSide[Y],locale)});const srAngleEndingSide=strings.srAngleEndingSide({x:srFormatNumber(endingSide[X],locale),y:srFormatNumber(endingSide[Y],locale)});const srAngleVertex=strings.srAngleVertexWithAngleMeasure({x:srFormatNumber(vertex[X],locale),y:srFormatNumber(vertex[Y],locale),angleMeasure});return {srAngleGraphAriaLabel,srAngleGraphAriaDescription,srAngleStartingSide,srAngleEndingSide,srAngleVertex}}const positiveX=[1,0];const negativeX=[-1,0];const positiveY=[0,1];const negativeY=[0,-1];function getAngleSideConstraint(sidePoint,vertex,snapDegrees){const currentAngle=calculateAngleInDegrees$2(mafs.vec.sub(sidePoint,vertex));const leftRay=[sidePoint,mafs.vec.add(sidePoint,negativeX)];const rightRay=[sidePoint,mafs.vec.add(sidePoint,positiveX)];const upRay=[sidePoint,mafs.vec.add(sidePoint,positiveY)];const downRay=[sidePoint,mafs.vec.add(sidePoint,negativeY)];const oneStepCounterClockwise=currentAngle+snapDegrees;const oneStepClockwise=currentAngle-snapDegrees;const counterClockwiseRay=[vertex,mafs.vec.add(vertex,polar$1(1,oneStepCounterClockwise))];const clockwiseRay=[vertex,mafs.vec.add(vertex,polar$1(1,oneStepClockwise))];const left=findIntersectionOfRays(leftRay,counterClockwiseRay)??findIntersectionOfRays(leftRay,clockwiseRay);const right=findIntersectionOfRays(rightRay,counterClockwiseRay)??findIntersectionOfRays(rightRay,clockwiseRay);const up=findIntersectionOfRays(upRay,counterClockwiseRay)??findIntersectionOfRays(upRay,clockwiseRay);const down=findIntersectionOfRays(downRay,counterClockwiseRay)??findIntersectionOfRays(downRay,clockwiseRay);return {up:up??sidePoint,down:down??sidePoint,left:left??sidePoint,right:right??sidePoint}}
2012
2012
 
2013
2013
  function getGradableGraph(state,initialGraph){if(!state.hasBeenInteractedWith){return {...initialGraph}}if(initialGraph.type==="linear-system"&&state.type==="linear-system"){return {...initialGraph,coords:state.coords}}if(state.type==="segment"&&initialGraph.type==="segment"){return {...initialGraph,coords:state.coords}}if(state.type==="linear"&&initialGraph.type==="linear"){return {...initialGraph,coords:state.coords}}if(state.type==="ray"&&initialGraph.type==="ray"){return {...initialGraph,coords:state.coords}}if(state.type==="vector"&&initialGraph.type==="vector"){return {...initialGraph,coords:state.coords}}if(state.type==="polygon"&&initialGraph.type==="polygon"){if(state.numSides==="unlimited"&&!state.closedPolygon){return {...initialGraph,coords:null}}return {...initialGraph,coords:state.coords}}if(state.type==="point"&&initialGraph.type==="point"){if(state.numPoints==="unlimited"&&state.coords.length===0){return {...initialGraph,coords:null}}return {...initialGraph,coords:state.coords}}if(state.type==="circle"&&initialGraph.type==="circle"){return {...initialGraph,center:state.center,radius:getRadius(state)}}if(state.type==="quadratic"&&initialGraph.type==="quadratic"){return {...initialGraph,coords:state.coords}}if(state.type==="sinusoid"&&initialGraph.type==="sinusoid"){return {...initialGraph,coords:state.coords}}if(state.type==="exponential"&&initialGraph.type==="exponential"){return {...initialGraph,coords:state.coords,asymptote:state.asymptote}}if(state.type==="logarithm"&&initialGraph.type==="logarithm"){return {...initialGraph,coords:state.coords,asymptote:state.asymptote}}if(state.type==="tangent"&&initialGraph.type==="tangent"){return {...initialGraph,coords:state.coords}}if(state.type==="angle"&&initialGraph.type==="angle"){return {...initialGraph,coords:state.coords,allowReflexAngles:state.allowReflexAngles}}if(state.type==="none"&&initialGraph.type==="none"){return {type:"none"}}if(state.type==="absolute-value"&&initialGraph.type==="absolute-value"){return {...initialGraph,coords:state.coords}}throw new Error("Mafs is not yet implemented for graph type: "+initialGraph.type)}function getRadius(graph){const[centerX,centerY]=graph.center;const[edgeX,edgeY]=graph.radiusPoint;return Math.sqrt(Math.pow(edgeX-centerX,2)+Math.pow(edgeY-centerY,2))}
2014
2014
 
@@ -2016,49 +2016,49 @@ function renderCircleGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.
2016
2016
 
2017
2017
  const ACTIVE_MAJOR=22;const ACTIVE_MINOR=12;const INACTIVE_MAJOR=16;const INACTIVE_MINOR=6;const RING_PAD=2;const HALO_PAD=3;const FOCUS_RING_PAD=2;const GRIP_DOT_MAJOR_OFFSETS=[-3,0,3];const GRIP_DOT_MINOR_OFFSETS=[-2,2];function MovablePillHandle(props){const{center,active,focused,rotation=0}=props;const[cx,cy]=center;const{interactiveColor}=useGraphConfig();const majorSize=active?ACTIVE_MAJOR:INACTIVE_MAJOR;const minorSize=active?ACTIVE_MINOR:INACTIVE_MINOR;const pillW=majorSize;const pillH=minorSize;const pillRadius=pillH/2;const haloW=pillW+(RING_PAD+HALO_PAD)*2;const haloH=pillH+(RING_PAD+HALO_PAD)*2;const haloRadius=haloH/2;const ringW=pillW+RING_PAD*2;const ringH=pillH+RING_PAD*2;const ringRadius=ringH/2;const focusRingW=haloW+FOCUS_RING_PAD*2;const focusRingH=haloH+FOCUS_RING_PAD*2;const focusRingRadius=focusRingH/2;return jsxRuntimeExports.jsxs("g",{"aria-hidden":true,style:{pointerEvents:"none"},transform:`translate(${cx} ${cy}) rotate(${rotation})`,"data-testid":"movable-pill-handle",children:[focused&&jsxRuntimeExports.jsx("rect",{className:"movable-pill-handle-focus-ring","data-testid":"movable-pill-handle-focus-ring",x:-focusRingW/2,y:-focusRingH/2,width:focusRingW,height:focusRingH,rx:focusRingRadius,ry:focusRingRadius,stroke:interactiveColor}),jsxRuntimeExports.jsx("rect",{className:"movable-pill-handle-halo",x:-haloW/2,y:-haloH/2,width:haloW,height:haloH,rx:haloRadius,ry:haloRadius,fill:interactiveColor}),jsxRuntimeExports.jsx("rect",{className:"movable-pill-handle-ring",x:-ringW/2,y:-ringH/2,width:ringW,height:ringH,rx:ringRadius,ry:ringRadius}),jsxRuntimeExports.jsx("rect",{className:"movable-pill-handle","data-testid":"movable-pill-handle-pill",x:-pillW/2,y:-pillH/2,width:pillW,height:pillH,rx:pillRadius,ry:pillRadius,fill:interactiveColor}),active&&GRIP_DOT_MINOR_OFFSETS.map(dy=>GRIP_DOT_MAJOR_OFFSETS.map(dx=>jsxRuntimeExports.jsx("circle",{className:"movable-pill-handle-dot","data-testid":"movable-pill-handle-dot",cx:dx,cy:dy},`${dx},${dy}`)))]})}
2018
2018
 
2019
- function MovableAsymptote(props){const{start,end,mid,point,onMove,constrainKeyboardMovement,orientation,ariaLabel,ariaLive,children}=props;const{interactiveColor,disableKeyboardInteraction}=useGraphConfig();const[focused,setFocused]=React__namespace.useState(false);const[hovered,setHovered]=React__namespace.useState(false);const groupRef=React__namespace.useRef(null);const{dragging}=useDraggable({gestureTarget:groupRef,point,onMove,constrainKeyboardMovement:constrainKeyboardMovement??(p=>p)});React__namespace.useLayoutEffect(()=>{if(dragging&&!focused){groupRef.current?.focus();}},[dragging,focused]);return jsxRuntimeExports.jsxs("g",{ref:groupRef,tabIndex:disableKeyboardInteraction?-1:0,"aria-disabled":disableKeyboardInteraction,"aria-label":ariaLabel,"aria-live":ariaLive??"polite",className:"movable-line",style:{cursor:dragging?"grabbing":"grab"},role:"button","data-testid":"movable-asymptote",onFocus:()=>setFocused(true),onBlur:()=>setFocused(false),onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),children:[jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:wonderBlocksTokens.semanticColor.core.background.base.default,strokeWidth:"var(--movable-asymptote-stroke-weight)",strokeLinecap:"round"},className:dragging?"movable-dragging":""}),jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:interactiveColor,strokeWidth:"var(--movable-asymptote-stroke-weight)",strokeDasharray:"var(--movable-asymptote-dash-length) var(--movable-asymptote-dash-gap)",strokeLinecap:"round"},className:dragging?"movable-dragging":"",testId:"movable-asymptote__line"}),children,jsxRuntimeExports.jsx(MovablePillHandle,{center:mid,rotation:orientation==="vertical"?90:0,active:dragging||focused||hovered,focused:focused})]})}
2019
+ function MovableAsymptote(props){const{start,end,mid,point,onMove,constrainKeyboardMovement,orientation,ariaLabel,children}=props;const{interactiveColor,disableKeyboardInteraction}=useGraphConfig();const[focused,setFocused]=React__namespace.useState(false);const[hovered,setHovered]=React__namespace.useState(false);const groupRef=React__namespace.useRef(null);const{dragging}=useDraggable({gestureTarget:groupRef,point,onMove,constrainKeyboardMovement:constrainKeyboardMovement??(p=>p)});React__namespace.useLayoutEffect(()=>{if(dragging&&!focused){groupRef.current?.focus();}},[dragging,focused]);return jsxRuntimeExports.jsxs("g",{ref:groupRef,tabIndex:disableKeyboardInteraction?-1:0,"aria-disabled":disableKeyboardInteraction,"aria-label":ariaLabel,className:"movable-line",style:{cursor:dragging?"grabbing":"grab"},role:"button","data-testid":"movable-asymptote",onFocus:()=>setFocused(true),onBlur:()=>setFocused(false),onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),children:[jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:wonderBlocksTokens.semanticColor.core.background.base.default,strokeWidth:"var(--movable-asymptote-stroke-weight)",strokeLinecap:"round"},className:dragging?"movable-dragging":""}),jsxRuntimeExports.jsx(SVGLine,{start:start,end:end,style:{stroke:interactiveColor,strokeWidth:"var(--movable-asymptote-stroke-weight)",strokeDasharray:"var(--movable-asymptote-dash-length) var(--movable-asymptote-dash-gap)",strokeLinecap:"round"},className:dragging?"movable-dragging":"",testId:"movable-asymptote__line"}),children,jsxRuntimeExports.jsx(MovablePillHandle,{center:mid,rotation:orientation==="vertical"?90:0,active:dragging||focused||hovered,focused:focused})]})}
2020
2020
 
2021
- const{getExponentialCoefficients}=kmath.coefficients;function renderExponentialGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(ExponentialGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getExponentialDescription(state,i18n)}}function ExponentialGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,asymptote,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffs=getExponentialCoefficients(coords,asymptote);const asymptoteY=asymptote;const yMin=range[1][0];const yMax=range[1][1];const yPadding=(yMax-yMin)*4;const{srExponentialGraph,srExponentialDescription,srExponentialPoint1,srExponentialPoint2,srExponentialAsymptote}=describeExponentialGraph(graphState,i18n);const asymptoteLeft=[range[0][0],asymptoteY];const asymptoteRight=[range[0][1],asymptoteY];const handleCoord=getAsymptoteHandleCoord("horizontal",range,asymptote);const[leftPx,rightPx,midPx]=useTransformVectorsToPixels(asymptoteLeft,asymptoteRight,handleCoord);return jsxRuntimeExports.jsxs("g",{"aria-label":srExponentialGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(MovableAsymptote,{start:leftPx,end:rightPx,mid:midPx,point:handleCoord,onMove:newPoint=>dispatch(actions.exponential.moveCenter(newPoint)),constrainKeyboardMovement:p=>skipAsymptoteKeyboardOverPoint(p,asymptote,coords,handleCoord,snapStep,"horizontal"),orientation:"horizontal",ariaLabel:srExponentialAsymptote,ariaLive:"off",children:coeffs!==undefined&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>{const y=computeExponential(x,coeffs);if(y<yMin-yPadding||y>yMax+yPadding){return NaN}return y},color:interactiveColor,svgPathProps:{"aria-hidden":true,style:{pointerEvents:"none"}}})})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srExponentialPoint1:srExponentialPoint2),point:coord,sequenceNumber:i+1,constrain:getExponentialKeyboardConstraint(coords,asymptote,snapStep,i,range),onMove:destination=>dispatch(actions.exponential.movePoint(i,destination)),ariaLive:"off"},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srExponentialDescription})]})}const getExponentialKeyboardConstraint=(coords,asymptote,snapStep,pointIndex,range)=>{const otherPoint=coords[1-pointIndex];const handleCoord=getAsymptoteHandleCoord("horizontal",range,asymptote);return getAsymptoteGraphKeyboardConstraint(coords,snapStep,pointIndex,coord=>{const clamped=boundToEdgeAndSnapToGrid(coord,{snapStep,range});const clampedX=clamped[X];const clampedY=clamped[Y];if(coord[X]===otherPoint[X]||clampedX===otherPoint[X]){return false}if(clampedX===handleCoord[X]&&clampedY===handleCoord[Y]){return false}return true})};const computeExponential=function(x,coefficients){const{a,b,c}=coefficients;return a*Math.exp(b*x)+c};function getExponentialDescription(state,i18n){const strings=describeExponentialGraph(state,i18n);return strings.srExponentialInteractiveElements}function describeExponentialGraph(state,i18n){const{strings,locale}=i18n;const{coords,asymptote}=state;const[point1,point2]=coords;const formattedPoint1={x:srFormatNumber(point1[X],locale),y:srFormatNumber(point1[Y],locale)};const formattedPoint2={x:srFormatNumber(point2[X],locale),y:srFormatNumber(point2[Y],locale)};const asymptoteYFormatted=srFormatNumber(asymptote,locale);return {srExponentialGraph:strings.srExponentialGraph,srExponentialDescription:strings.srExponentialDescription({point1X:formattedPoint1.x,point1Y:formattedPoint1.y,point2X:formattedPoint2.x,point2Y:formattedPoint2.y,asymptoteY:asymptoteYFormatted}),srExponentialAsymptote:strings.srExponentialAsymptote({asymptoteY:asymptoteYFormatted}),srExponentialPoint1:strings.srExponentialPoint1(formattedPoint1),srExponentialPoint2:strings.srExponentialPoint2(formattedPoint2),srExponentialInteractiveElements:strings.srInteractiveElements({elements:strings.srExponentialInteractiveElements({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),asymptoteY:asymptoteYFormatted})})}}
2021
+ const{getExponentialCoefficients}=kmath.coefficients;function renderExponentialGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(ExponentialGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getExponentialDescription(state,i18n)}}function ExponentialGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,asymptote,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffs=getExponentialCoefficients(coords,asymptote);const asymptoteY=asymptote;const yMin=range[1][0];const yMax=range[1][1];const yPadding=(yMax-yMin)*4;const{srExponentialGraph,srExponentialDescription,srExponentialPoint1,srExponentialPoint2,srExponentialAsymptote}=describeExponentialGraph(graphState,i18n);const asymptoteLeft=[range[0][0],asymptoteY];const asymptoteRight=[range[0][1],asymptoteY];const handleCoord=getAsymptoteHandleCoord("horizontal",range,asymptote);const[leftPx,rightPx,midPx]=useTransformVectorsToPixels(asymptoteLeft,asymptoteRight,handleCoord);return jsxRuntimeExports.jsxs("g",{"aria-label":srExponentialGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(MovableAsymptote,{start:leftPx,end:rightPx,mid:midPx,point:handleCoord,onMove:newPoint=>dispatch(actions.exponential.moveCenter(newPoint)),constrainKeyboardMovement:p=>skipAsymptoteKeyboardOverPoint(p,asymptote,coords,handleCoord,snapStep,"horizontal"),orientation:"horizontal",ariaLabel:srExponentialAsymptote,children:coeffs!==undefined&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>{const y=computeExponential(x,coeffs);if(y<yMin-yPadding||y>yMax+yPadding){return NaN}return y},color:interactiveColor,svgPathProps:{"aria-hidden":true,style:{pointerEvents:"none"}}})})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srExponentialPoint1:srExponentialPoint2),point:coord,sequenceNumber:i+1,constrain:getExponentialKeyboardConstraint(coords,asymptote,snapStep,i,range),onMove:destination=>dispatch(actions.exponential.movePoint(i,destination))},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srExponentialDescription})]})}const getExponentialKeyboardConstraint=(coords,asymptote,snapStep,pointIndex,range)=>{const otherPoint=coords[1-pointIndex];const handleCoord=getAsymptoteHandleCoord("horizontal",range,asymptote);return getAsymptoteGraphKeyboardConstraint(coords,snapStep,pointIndex,coord=>{const clamped=boundToEdgeAndSnapToGrid(coord,{snapStep,range});const clampedX=clamped[X];const clampedY=clamped[Y];if(coord[X]===otherPoint[X]||clampedX===otherPoint[X]){return false}if(clampedX===handleCoord[X]&&clampedY===handleCoord[Y]){return false}return true})};const computeExponential=function(x,coefficients){const{a,b,c}=coefficients;return a*Math.exp(b*x)+c};function getExponentialDescription(state,i18n){const strings=describeExponentialGraph(state,i18n);return strings.srExponentialInteractiveElements}function describeExponentialGraph(state,i18n){const{strings,locale}=i18n;const{coords,asymptote}=state;const[point1,point2]=coords;const formattedPoint1={x:srFormatNumber(point1[X],locale),y:srFormatNumber(point1[Y],locale)};const formattedPoint2={x:srFormatNumber(point2[X],locale),y:srFormatNumber(point2[Y],locale)};const asymptoteYFormatted=srFormatNumber(asymptote,locale);return {srExponentialGraph:strings.srExponentialGraph,srExponentialDescription:strings.srExponentialDescription({point1X:formattedPoint1.x,point1Y:formattedPoint1.y,point2X:formattedPoint2.x,point2Y:formattedPoint2.y,asymptoteY:asymptoteYFormatted}),srExponentialAsymptote:strings.srExponentialAsymptote({asymptoteY:asymptoteYFormatted}),srExponentialPoint1:strings.srExponentialPoint1(formattedPoint1),srExponentialPoint2:strings.srExponentialPoint2(formattedPoint2),srExponentialInteractiveElements:strings.srInteractiveElements({elements:strings.srExponentialInteractiveElements({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),asymptoteY:asymptoteYFormatted})})}}
2022
2022
 
2023
- function renderLinearGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LinearGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLinearGraphDescription(state,i18n)}}const LinearGraph=(props,key)=>{const{dispatch}=props;const{coords:line,pointLabels}=props.graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const interceptDescriptionId=id+"-intercept";const slopeDescriptionId=id+"-slope";const{srLinearGraph,srLinearGraphPoints,srLinearGrabHandle,slopeString,interceptString}=describeLinearGraph(props.graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srLinearGraph,"aria-describedby":`${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`,children:[jsxRuntimeExports.jsx(MovableLine,{ariaLabels:{grabHandleAriaLabel:srLinearGrabHandle,point1AriaLabel:buildLabel(0,line[0]),point2AriaLabel:buildLabel(1,line[1])},ariaDescribedBy:`${interceptDescriptionId} ${slopeDescriptionId}`,ariaLive:"off",points:line,onMoveLine:newStart=>{dispatch(actions.linear.moveLine(newStart));},extend:{start:true,end:true},onMovePoint:(endpointIndex,destination)=>dispatch(actions.linear.movePoint(endpointIndex,destination))},0),jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srLinearGraphPoints}),jsxRuntimeExports.jsx(SRDescInSVG,{id:interceptDescriptionId,children:interceptString}),jsxRuntimeExports.jsx(SRDescInSVG,{id:slopeDescriptionId,children:slopeString})]})};function getLinearGraphDescription(state,i18n){const strings=describeLinearGraph(state,i18n);return strings.srLinearInteractiveElement}function describeLinearGraph(state,i18n){const{coords:line}=state;const{strings,locale}=i18n;const srLinearGraph=strings.srLinearGraph;const srLinearGraphPoints=strings.srLinearGraphPoints({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srLinearGrabHandle=strings.srLinearGrabHandle({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const slopeString=getSlopeStringForLine(line,strings);const interceptString=getInterceptStringForLine(line,strings,locale);const srLinearInteractiveElement=strings.srInteractiveElements({elements:[srLinearGraph,srLinearGraphPoints].join(" ")});return {srLinearGraph,srLinearGraphPoints,srLinearGrabHandle,slopeString,interceptString,srLinearInteractiveElement}}
2023
+ function renderLinearGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LinearGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLinearGraphDescription(state,i18n)}}const LinearGraph=(props,key)=>{const{dispatch}=props;const{coords:line,pointLabels}=props.graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const interceptDescriptionId=id+"-intercept";const slopeDescriptionId=id+"-slope";const{srLinearGraph,srLinearGraphPoints,srLinearGrabHandle,slopeString,interceptString}=describeLinearGraph(props.graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srLinearGraph,"aria-describedby":`${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`,children:[jsxRuntimeExports.jsx(MovableLine,{ariaLabels:{grabHandleAriaLabel:srLinearGrabHandle,point1AriaLabel:buildLabel(0,line[0]),point2AriaLabel:buildLabel(1,line[1])},ariaDescribedBy:`${interceptDescriptionId} ${slopeDescriptionId}`,points:line,onMoveLine:newStart=>{dispatch(actions.linear.moveLine(newStart));},extend:{start:true,end:true},onMovePoint:(endpointIndex,destination)=>dispatch(actions.linear.movePoint(endpointIndex,destination))},0),jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srLinearGraphPoints}),jsxRuntimeExports.jsx(SRDescInSVG,{id:interceptDescriptionId,children:interceptString}),jsxRuntimeExports.jsx(SRDescInSVG,{id:slopeDescriptionId,children:slopeString})]})};function getLinearGraphDescription(state,i18n){const strings=describeLinearGraph(state,i18n);return strings.srLinearInteractiveElement}function describeLinearGraph(state,i18n){const{coords:line}=state;const{strings,locale}=i18n;const srLinearGraph=strings.srLinearGraph;const srLinearGraphPoints=strings.srLinearGraphPoints({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srLinearGrabHandle=strings.srLinearGrabHandle({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const slopeString=getSlopeStringForLine(line,strings);const interceptString=getInterceptStringForLine(line,strings,locale);const srLinearInteractiveElement=strings.srInteractiveElements({elements:[srLinearGraph,srLinearGraphPoints].join(" ")});return {srLinearGraph,srLinearGraphPoints,srLinearGrabHandle,slopeString,interceptString,srLinearInteractiveElement}}
2024
2024
 
2025
- function renderLinearSystemGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LinearSystemGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLinearSystemGraphDescription(state,i18n)}}const LinearSystemGraph=props=>{const{dispatch}=props;const{coords:lines,pointLabels}=props.graphState;const{strings,locale}=usePerseusI18n();const id=React__namespace.useId();const intersectionId=`${id}-intersection`;const buildLabel=usePointAriaLabel(pointLabels);const intersectionPoint=kmath.geometry.getLineIntersection(lines[0],lines[1]);const intersectionDescription=intersectionPoint?strings.srLinearSystemIntersection({x:srFormatNumber(intersectionPoint[0],locale),y:srFormatNumber(intersectionPoint[1],locale)}):strings.srLinearSystemParallel;const linesAriaInfo=lines.map((line,i)=>{return {pointsDescriptionId:`${id}-line${i+1}-points`,interceptDescriptionId:`${id}-line${i+1}-intercept`,slopeDescriptionId:`${id}-line${i+1}-slope`,pointsDescription:strings.srLinearSystemPoints({lineNumber:i+1,point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)}),interceptDescription:getInterceptStringForLine(line,strings,locale),slopeDescription:getSlopeStringForLine(line,strings)}});const individualLineDescriptions=linesAriaInfo.map(({pointsDescriptionId,interceptDescriptionId,slopeDescriptionId})=>`${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`).join(" ");return jsxRuntimeExports.jsxs("g",{"aria-label":strings.srLinearSystemGraph,"aria-describedby":`${individualLineDescriptions} ${intersectionId}`,children:[lines?.map((line,i)=>jsxRuntimeExports.jsx(MovableLine,{points:line,ariaLive:"off",ariaLabels:{point1AriaLabel:buildLabel(i*2,line[0])??strings.srLinearSystemPoint({lineNumber:i+1,pointSequence:1,x:srFormatNumber(line[0][0],locale),y:srFormatNumber(line[0][1],locale)}),point2AriaLabel:buildLabel(i*2+1,line[1])??strings.srLinearSystemPoint({lineNumber:i+1,pointSequence:2,x:srFormatNumber(line[1][0],locale),y:srFormatNumber(line[1][1],locale)}),grabHandleAriaLabel:strings.srLinearSystemGrabHandle({lineNumber:i+1,point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)})},ariaDescribedBy:`${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId} ${intersectionId}`,onMoveLine:newStart=>{dispatch(actions.linearSystem.moveLine(i,newStart));},extend:{start:true,end:true},onMovePoint:(endpointIndex,destination)=>dispatch(actions.linearSystem.movePointInFigure(i,endpointIndex,destination))},i)),linesAriaInfo.map(({pointsDescriptionId,interceptDescriptionId,slopeDescriptionId,pointsDescription,interceptDescription,slopeDescription},i)=>jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:pointsDescription}),jsxRuntimeExports.jsx(SRDescInSVG,{id:interceptDescriptionId,children:interceptDescription}),jsxRuntimeExports.jsx(SRDescInSVG,{id:slopeDescriptionId,children:slopeDescription})]},`line-descriptions-${i}`)),jsxRuntimeExports.jsx(SRDescInSVG,{id:intersectionId,children:intersectionDescription})]})};function getLinearSystemGraphDescription(state,i18n){const{strings,locale}=i18n;const{coords:lines}=state;const graphDescription=strings.srLinearSystemGraph;const lineDescriptions=lines.map((line,i)=>{const point1=line[0];const point2=line[1];return strings.srLinearSystemPoints({lineNumber:i+1,point1X:srFormatNumber(point1[0],locale),point1Y:srFormatNumber(point1[1],locale),point2X:srFormatNumber(point2[0],locale),point2Y:srFormatNumber(point2[1],locale)})});const allDescriptions=[graphDescription,...lineDescriptions];return strings.srInteractiveElements({elements:allDescriptions.join(" ")})}
2025
+ function renderLinearSystemGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LinearSystemGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLinearSystemGraphDescription(state,i18n)}}const LinearSystemGraph=props=>{const{dispatch}=props;const{coords:lines,pointLabels}=props.graphState;const{strings,locale}=usePerseusI18n();const id=React__namespace.useId();const intersectionId=`${id}-intersection`;const buildLabel=usePointAriaLabel(pointLabels);const intersectionPoint=kmath.geometry.getLineIntersection(lines[0],lines[1]);const intersectionDescription=intersectionPoint?strings.srLinearSystemIntersection({x:srFormatNumber(intersectionPoint[0],locale),y:srFormatNumber(intersectionPoint[1],locale)}):strings.srLinearSystemParallel;const linesAriaInfo=lines.map((line,i)=>{return {pointsDescriptionId:`${id}-line${i+1}-points`,interceptDescriptionId:`${id}-line${i+1}-intercept`,slopeDescriptionId:`${id}-line${i+1}-slope`,pointsDescription:strings.srLinearSystemPoints({lineNumber:i+1,point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)}),interceptDescription:getInterceptStringForLine(line,strings,locale),slopeDescription:getSlopeStringForLine(line,strings)}});const individualLineDescriptions=linesAriaInfo.map(({pointsDescriptionId,interceptDescriptionId,slopeDescriptionId})=>`${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`).join(" ");return jsxRuntimeExports.jsxs("g",{"aria-label":strings.srLinearSystemGraph,"aria-describedby":`${individualLineDescriptions} ${intersectionId}`,children:[lines?.map((line,i)=>jsxRuntimeExports.jsx(MovableLine,{points:line,ariaLabels:{point1AriaLabel:buildLabel(i*2,line[0])??strings.srLinearSystemPoint({lineNumber:i+1,pointSequence:1,x:srFormatNumber(line[0][0],locale),y:srFormatNumber(line[0][1],locale)}),point2AriaLabel:buildLabel(i*2+1,line[1])??strings.srLinearSystemPoint({lineNumber:i+1,pointSequence:2,x:srFormatNumber(line[1][0],locale),y:srFormatNumber(line[1][1],locale)}),grabHandleAriaLabel:strings.srLinearSystemGrabHandle({lineNumber:i+1,point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)})},ariaDescribedBy:`${linesAriaInfo[i].interceptDescriptionId} ${linesAriaInfo[i].slopeDescriptionId} ${intersectionId}`,onMoveLine:newStart=>{dispatch(actions.linearSystem.moveLine(i,newStart));},extend:{start:true,end:true},onMovePoint:(endpointIndex,destination)=>dispatch(actions.linearSystem.movePointInFigure(i,endpointIndex,destination))},i)),linesAriaInfo.map(({pointsDescriptionId,interceptDescriptionId,slopeDescriptionId,pointsDescription,interceptDescription,slopeDescription},i)=>jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:pointsDescription}),jsxRuntimeExports.jsx(SRDescInSVG,{id:interceptDescriptionId,children:interceptDescription}),jsxRuntimeExports.jsx(SRDescInSVG,{id:slopeDescriptionId,children:slopeDescription})]},`line-descriptions-${i}`)),jsxRuntimeExports.jsx(SRDescInSVG,{id:intersectionId,children:intersectionDescription})]})};function getLinearSystemGraphDescription(state,i18n){const{strings,locale}=i18n;const{coords:lines}=state;const graphDescription=strings.srLinearSystemGraph;const lineDescriptions=lines.map((line,i)=>{const point1=line[0];const point2=line[1];return strings.srLinearSystemPoints({lineNumber:i+1,point1X:srFormatNumber(point1[0],locale),point1Y:srFormatNumber(point1[1],locale),point2X:srFormatNumber(point2[0],locale),point2Y:srFormatNumber(point2[1],locale)})});const allDescriptions=[graphDescription,...lineDescriptions];return strings.srInteractiveElements({elements:allDescriptions.join(" ")})}
2026
2026
 
2027
- const{getLogarithmCoefficients}=kmath.coefficients;function renderLogarithmGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LogarithmGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLogarithmDescription(state,i18n)}}function LogarithmGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,asymptote,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffs=getLogarithmCoefficients(coords,asymptote);const asymptoteX=asymptote;const xMin=range[0][0];const xMax=range[0][1];const yMin=range[1][0];const yMax=range[1][1];const{srLogarithmGraph,srLogarithmDescription,srLogarithmPoint1,srLogarithmPoint2,srLogarithmAsymptote}=describeLogarithmGraph(graphState,i18n);const asymptoteBottom=[asymptoteX,yMin];const asymptoteTop=[asymptoteX,yMax];const handleCoord=getAsymptoteHandleCoord("vertical",range,asymptote);const[bottomPx,topPx,midPx]=useTransformVectorsToPixels(asymptoteBottom,asymptoteTop,handleCoord);return jsxRuntimeExports.jsxs("g",{"aria-label":srLogarithmGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(MovableAsymptote,{start:bottomPx,end:topPx,mid:midPx,point:handleCoord,onMove:newPoint=>dispatch(actions.logarithm.moveCenter(newPoint)),constrainKeyboardMovement:p=>skipAsymptoteKeyboardOverPoint(p,asymptote,coords,handleCoord,snapStep,"vertical"),orientation:"vertical",ariaLabel:srLogarithmAsymptote,ariaLive:"off",children:coeffs!==undefined&&renderLogarithmCurve({coeffs,coords,asymptoteX,xMin,xMax,yMin,yMax,interactiveColor})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srLogarithmPoint1:srLogarithmPoint2),point:coord,sequenceNumber:i+1,constrain:getLogarithmKeyboardConstraint(coords,asymptote,snapStep,i,range),onMove:destination=>dispatch(actions.logarithm.movePoint(i,destination)),ariaLive:"off"},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srLogarithmDescription})]})}const getLogarithmKeyboardConstraint=(coords,asymptote,snapStep,pointIndex,range)=>{const otherPoint=coords[1-pointIndex];const handleCoord=getAsymptoteHandleCoord("vertical",range,asymptote);return getAsymptoteGraphKeyboardConstraint(coords,snapStep,pointIndex,coord=>{const clamped=boundToEdgeAndSnapToGrid(coord,{snapStep,range});const clampedX=clamped[X];const clampedY=clamped[Y];if(coord[X]===otherPoint[X]||clampedX===otherPoint[X]){return false}if(coord[Y]===otherPoint[Y]||clampedY===otherPoint[Y]){return false}if(clampedX===handleCoord[X]&&clampedY===handleCoord[Y]){return false}return true})};const computeLogarithm=function(coefficients,x){const{a,b,c}=coefficients;const arg=b*x+c;if(arg<=0){return NaN}return a*Math.log(arg)};function renderLogarithmCurve({coeffs,coords,asymptoteX,xMin,xMax,yMin,yMax,interactiveColor}){const offScreenMargin=2;const{a,b,c}=coeffs;const targetY=a>0?yMin-offScreenMargin:yMax+offScreenMargin;const computedX=(Math.exp(targetY/a)-c)/b;const computedOffset=Math.abs(computedX-asymptoteX);const domainOffset=isFinite(computedOffset)&&computedOffset>0?computedOffset:1e-8;const pointsRightOfAsymptote=coords[0][X]>asymptoteX;return jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeLogarithm(coeffs,x),color:interactiveColor,svgPathProps:{"aria-hidden":true,style:{pointerEvents:"none"}},domain:pointsRightOfAsymptote?[asymptoteX+domainOffset,xMax]:[xMin,asymptoteX-domainOffset]})})}function getLogarithmDescription(state,i18n){const strings=describeLogarithmGraph(state,i18n);return strings.srLogarithmInteractiveElements}function describeLogarithmGraph(state,i18n){const{strings,locale}=i18n;const{coords,asymptote}=state;const[point1,point2]=coords;const formattedPoint1={x:srFormatNumber(point1[X],locale),y:srFormatNumber(point1[Y],locale)};const formattedPoint2={x:srFormatNumber(point2[X],locale),y:srFormatNumber(point2[Y],locale)};const asymptoteXFormatted=srFormatNumber(asymptote,locale);return {srLogarithmGraph:strings.srLogarithmGraph,srLogarithmDescription:strings.srLogarithmDescription({point1X:formattedPoint1.x,point1Y:formattedPoint1.y,point2X:formattedPoint2.x,point2Y:formattedPoint2.y,asymptoteX:asymptoteXFormatted}),srLogarithmAsymptote:strings.srLogarithmAsymptote({asymptoteX:asymptoteXFormatted}),srLogarithmPoint1:strings.srLogarithmPoint1(formattedPoint1),srLogarithmPoint2:strings.srLogarithmPoint2(formattedPoint2),srLogarithmInteractiveElements:strings.srInteractiveElements({elements:strings.srLogarithmInteractiveElements({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),asymptoteX:asymptoteXFormatted})})}}
2027
+ const{getLogarithmCoefficients}=kmath.coefficients;function renderLogarithmGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(LogarithmGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getLogarithmDescription(state,i18n)}}function LogarithmGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,asymptote,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffs=getLogarithmCoefficients(coords,asymptote);const asymptoteX=asymptote;const xMin=range[0][0];const xMax=range[0][1];const yMin=range[1][0];const yMax=range[1][1];const{srLogarithmGraph,srLogarithmDescription,srLogarithmPoint1,srLogarithmPoint2,srLogarithmAsymptote}=describeLogarithmGraph(graphState,i18n);const asymptoteBottom=[asymptoteX,yMin];const asymptoteTop=[asymptoteX,yMax];const handleCoord=getAsymptoteHandleCoord("vertical",range,asymptote);const[bottomPx,topPx,midPx]=useTransformVectorsToPixels(asymptoteBottom,asymptoteTop,handleCoord);return jsxRuntimeExports.jsxs("g",{"aria-label":srLogarithmGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(MovableAsymptote,{start:bottomPx,end:topPx,mid:midPx,point:handleCoord,onMove:newPoint=>dispatch(actions.logarithm.moveCenter(newPoint)),constrainKeyboardMovement:p=>skipAsymptoteKeyboardOverPoint(p,asymptote,coords,handleCoord,snapStep,"vertical"),orientation:"vertical",ariaLabel:srLogarithmAsymptote,children:coeffs!==undefined&&renderLogarithmCurve({coeffs,coords,asymptoteX,xMin,xMax,yMin,yMax,interactiveColor})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srLogarithmPoint1:srLogarithmPoint2),point:coord,sequenceNumber:i+1,constrain:getLogarithmKeyboardConstraint(coords,asymptote,snapStep,i,range),onMove:destination=>dispatch(actions.logarithm.movePoint(i,destination))},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srLogarithmDescription})]})}const getLogarithmKeyboardConstraint=(coords,asymptote,snapStep,pointIndex,range)=>{const otherPoint=coords[1-pointIndex];const handleCoord=getAsymptoteHandleCoord("vertical",range,asymptote);return getAsymptoteGraphKeyboardConstraint(coords,snapStep,pointIndex,coord=>{const clamped=boundToEdgeAndSnapToGrid(coord,{snapStep,range});const clampedX=clamped[X];const clampedY=clamped[Y];if(coord[X]===otherPoint[X]||clampedX===otherPoint[X]){return false}if(coord[Y]===otherPoint[Y]||clampedY===otherPoint[Y]){return false}if(clampedX===handleCoord[X]&&clampedY===handleCoord[Y]){return false}return true})};const computeLogarithm=function(coefficients,x){const{a,b,c}=coefficients;const arg=b*x+c;if(arg<=0){return NaN}return a*Math.log(arg)};function renderLogarithmCurve({coeffs,coords,asymptoteX,xMin,xMax,yMin,yMax,interactiveColor}){const offScreenMargin=2;const{a,b,c}=coeffs;const targetY=a>0?yMin-offScreenMargin:yMax+offScreenMargin;const computedX=(Math.exp(targetY/a)-c)/b;const computedOffset=Math.abs(computedX-asymptoteX);const domainOffset=isFinite(computedOffset)&&computedOffset>0?computedOffset:1e-8;const pointsRightOfAsymptote=coords[0][X]>asymptoteX;return jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeLogarithm(coeffs,x),color:interactiveColor,svgPathProps:{"aria-hidden":true,style:{pointerEvents:"none"}},domain:pointsRightOfAsymptote?[asymptoteX+domainOffset,xMax]:[xMin,asymptoteX-domainOffset]})})}function getLogarithmDescription(state,i18n){const strings=describeLogarithmGraph(state,i18n);return strings.srLogarithmInteractiveElements}function describeLogarithmGraph(state,i18n){const{strings,locale}=i18n;const{coords,asymptote}=state;const[point1,point2]=coords;const formattedPoint1={x:srFormatNumber(point1[X],locale),y:srFormatNumber(point1[Y],locale)};const formattedPoint2={x:srFormatNumber(point2[X],locale),y:srFormatNumber(point2[Y],locale)};const asymptoteXFormatted=srFormatNumber(asymptote,locale);return {srLogarithmGraph:strings.srLogarithmGraph,srLogarithmDescription:strings.srLogarithmDescription({point1X:formattedPoint1.x,point1Y:formattedPoint1.y,point2X:formattedPoint2.x,point2Y:formattedPoint2.y,asymptoteX:asymptoteXFormatted}),srLogarithmAsymptote:strings.srLogarithmAsymptote({asymptoteX:asymptoteXFormatted}),srLogarithmPoint1:strings.srLogarithmPoint1(formattedPoint1),srLogarithmPoint2:strings.srLogarithmPoint2(formattedPoint2),srLogarithmInteractiveElements:strings.srInteractiveElements({elements:strings.srLogarithmInteractiveElements({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),asymptoteX:asymptoteXFormatted})})}}
2028
2028
 
2029
- function renderPointGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(PointGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getPointGraphDescription(state,i18n)}}function PointGraph(props){const{numPoints}=props.graphState;const graphConfig=useGraphConfig();const pointsRef=React__namespace.useRef([]);const{range:[x,y]}=graphConfig;const[[left,top]]=useTransformVectorsToPixels([x[0],y[1]]);React__namespace.useEffect(()=>{const focusedIndex=props.graphState.focusedPointIndex;if(focusedIndex!=null){pointsRef.current[focusedIndex]?.focus();}},[props.graphState.focusedPointIndex,props.graphState.coords.length,pointsRef]);const statefulProps={...props,graphConfig,pointsRef,top,left};if(numPoints==="unlimited"){return UnlimitedPointGraph(statefulProps)}return LimitedPointGraph(statefulProps)}function LimitedPointGraph(statefulProps){const{dispatch}=statefulProps;const{pointLabels}=statefulProps.graphState;const buildLabel=usePointAriaLabel(pointLabels);return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:statefulProps.graphState.coords.map((point,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{point:point,sequenceNumber:i+1,ariaLive:"off",ariaLabel:buildLabel(i,point),onMove:destination=>dispatch(actions.pointGraph.movePoint(i,destination))},i))})}function UnlimitedPointGraph(statefulProps){const{dispatch,graphConfig,pointsRef,top,left}=statefulProps;const{coords,pointLabels}=statefulProps.graphState;const buildLabel=usePointAriaLabel(pointLabels);const[isCurrentlyDragging,setIsCurrentlyDragging]=React__namespace.useState(false);const dragEndCallbackTimer=wonderBlocksTiming.useTimeout(()=>setIsCurrentlyDragging(false),400);const{graphDimensionsInPixels}=graphConfig;const widthPx=graphDimensionsInPixels[0];const heightPx=graphDimensionsInPixels[1];return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("rect",{style:{fill:"rgba(0,0,0,0)",cursor:"crosshair"},width:widthPx,height:heightPx,x:left,y:top,onClick:event=>{if(isCurrentlyDragging){return}const elementRect=event.currentTarget.getBoundingClientRect();const zoomFactor=getCSSZoomFactor(event.currentTarget);const x=(event.clientX-elementRect.x)/zoomFactor;const y=(event.clientY-elementRect.y)/zoomFactor;const graphCoordinates=pixelsToVectors([[x,y]],graphConfig);dispatch(actions.pointGraph.addPoint(graphCoordinates[0]));}}),coords.map((point,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{point:point,sequenceNumber:i+1,ariaLive:"off",ariaLabel:buildLabel(i,point),onDragStart:()=>{dragEndCallbackTimer.clear();setIsCurrentlyDragging(true);},onMove:destination=>{dispatch(actions.pointGraph.movePoint(i,destination));},onDragEnd:()=>{dragEndCallbackTimer.set();},ref:ref=>{pointsRef.current[i]=ref;},onFocus:()=>{dispatch(actions.pointGraph.focusPoint(i));},onClick:()=>{dispatch(actions.pointGraph.clickPoint(i));}},i))]})}function getPointGraphDescription(state,i18n){const{strings,locale}=i18n;if(state.coords.length===0){return strings.srNoInteractiveElements}const pointDescriptions=state.coords.map((point,index)=>buildPointAriaLabel(state.pointLabels,index,point,strings,locale)??strings.srPointAtCoordinates({num:index+1,x:srFormatNumber(point[0],locale),y:srFormatNumber(point[1],locale)}));return strings.srInteractiveElements({elements:pointDescriptions.join(" ")})}
2029
+ function renderPointGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(PointGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getPointGraphDescription(state,i18n)}}function PointGraph(props){const{numPoints}=props.graphState;const graphConfig=useGraphConfig();const pointsRef=React__namespace.useRef([]);const{range:[x,y]}=graphConfig;const[[left,top]]=useTransformVectorsToPixels([x[0],y[1]]);React__namespace.useEffect(()=>{const focusedIndex=props.graphState.focusedPointIndex;if(focusedIndex!=null){pointsRef.current[focusedIndex]?.focus();}},[props.graphState.focusedPointIndex,props.graphState.coords.length,pointsRef]);const statefulProps={...props,graphConfig,pointsRef,top,left};if(numPoints==="unlimited"){return UnlimitedPointGraph(statefulProps)}return LimitedPointGraph(statefulProps)}function LimitedPointGraph(statefulProps){const{dispatch}=statefulProps;const{pointLabels}=statefulProps.graphState;const buildLabel=usePointAriaLabel(pointLabels);return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:statefulProps.graphState.coords.map((point,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{point:point,sequenceNumber:i+1,ariaLabel:buildLabel(i,point),onMove:destination=>dispatch(actions.pointGraph.movePoint(i,destination))},i))})}function UnlimitedPointGraph(statefulProps){const{dispatch,graphConfig,pointsRef,top,left}=statefulProps;const{coords,pointLabels}=statefulProps.graphState;const buildLabel=usePointAriaLabel(pointLabels);const[isCurrentlyDragging,setIsCurrentlyDragging]=React__namespace.useState(false);const dragEndCallbackTimer=wonderBlocksTiming.useTimeout(()=>setIsCurrentlyDragging(false),400);const{graphDimensionsInPixels}=graphConfig;const widthPx=graphDimensionsInPixels[0];const heightPx=graphDimensionsInPixels[1];return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("rect",{style:{fill:"rgba(0,0,0,0)",cursor:"crosshair"},width:widthPx,height:heightPx,x:left,y:top,onClick:event=>{if(isCurrentlyDragging){return}const elementRect=event.currentTarget.getBoundingClientRect();const zoomFactor=getCSSZoomFactor(event.currentTarget);const x=(event.clientX-elementRect.x)/zoomFactor;const y=(event.clientY-elementRect.y)/zoomFactor;const graphCoordinates=pixelsToVectors([[x,y]],graphConfig);dispatch(actions.pointGraph.addPoint(graphCoordinates[0]));}}),coords.map((point,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{point:point,sequenceNumber:i+1,ariaLabel:buildLabel(i,point),onDragStart:()=>{dragEndCallbackTimer.clear();setIsCurrentlyDragging(true);},onMove:destination=>{dispatch(actions.pointGraph.movePoint(i,destination));},onDragEnd:()=>{dragEndCallbackTimer.set();},ref:ref=>{pointsRef.current[i]=ref;},onFocus:()=>{dispatch(actions.pointGraph.focusPoint(i));},onClick:()=>{dispatch(actions.pointGraph.clickPoint(i));}},i))]})}function getPointGraphDescription(state,i18n){const{strings,locale}=i18n;if(state.coords.length===0){return strings.srNoInteractiveElements}const pointDescriptions=state.coords.map((point,index)=>buildPointAriaLabel(state.pointLabels,index,point,strings,locale)??strings.srPointAtCoordinates({num:index+1,x:srFormatNumber(point[0],locale),y:srFormatNumber(point[1],locale)}));return strings.srInteractiveElements({elements:pointDescriptions.join(" ")})}
2030
2030
 
2031
2031
  const{magnitude: magnitude$1,vector: vector$1}=kmath.geometry;function initializeGraphState(params){const{graph,step,snapStep,range}=params;const shared={hasBeenInteractedWith:false,range,snapStep,pointLabels:"pointLabels"in graph?graph.pointLabels:undefined,showPointLabels:"showPointLabels"in graph?Boolean(graph.showPointLabels):undefined};switch(graph.type){case "segment":return {...shared,type:"segment",coords:getSegmentCoords(graph,range,step)};case "linear":return {...shared,type:graph.type,coords:getLineCoords(graph,range,step)};case "ray":return {...shared,type:graph.type,coords:getLineCoords(graph,range,step)};case "linear-system":return {...shared,type:graph.type,coords:getLinearSystemCoords(graph,range,step)};case "polygon":return {...shared,type:"polygon",numSides:graph.numSides||0,showAngles:Boolean(graph.showAngles),showSides:Boolean(graph.showSides),coords:getPolygonCoords(graph,range,step),snapTo:graph.snapTo??"grid",focusedPointIndex:null,showRemovePointButton:false,interactionMode:"mouse",showKeyboardInteractionInvitation:false,closedPolygon:false};case "point":return {...shared,type:graph.type,coords:getPointCoords(graph,range,step),numPoints:graph.numPoints||0,focusedPointIndex:null,showRemovePointButton:false,interactionMode:"mouse",showKeyboardInteractionInvitation:false};case "circle":return {...shared,type:graph.type,...getCircleCoords(graph)};case "quadratic":return {...shared,type:graph.type,coords:getQuadraticCoords(graph,range,step)};case "sinusoid":return {...shared,type:graph.type,coords:getSinusoidCoords(graph,range,step)};case "exponential":return {...shared,type:graph.type,...getExponentialCoords(graph,range,step)};case "angle":return {...shared,type:graph.type,showAngles:Boolean(graph.showAngles),coords:getAngleCoords({graph,range,step}),angleOffsetDeg:graph.angleOffsetDeg??0,allowReflexAngles:Boolean(graph.allowReflexAngles),snapDegrees:Number(graph.snapDegrees)};case "none":return {...shared,type:"none"};case "absolute-value":return {...shared,type:graph.type,coords:getAbsoluteValueCoords(graph,range,step)};case "tangent":return {...shared,type:graph.type,coords:getTangentCoords(graph,range,step)};case "logarithm":return {...shared,type:graph.type,...getLogarithmCoords(graph,range,step)};case "vector":return {...shared,type:graph.type,coords:getVectorCoords(graph,range,step)};default:throw new wonderStuffCore.UnreachableCaseError(graph)}}function getPointCoords(graph,range,step){const numPoints=graph.numPoints||1;let coords=graph.coords?.slice();if(coords){return coords}const startCoords=graph.startCoords?.slice();if(startCoords){return startCoords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;default:coords=[];break}const newCoords=normalizeCoords$1(coords,[[-10,10],[-10,10]]);return normalizePoints(range,step,newCoords)}function getSegmentCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}const ys=n=>{switch(n){case 2:return [5,-5];case 3:return [5,0,-5];case 4:return [6,2,-2,-6];case 5:return [6,3,0,-3,-6];case 6:return [5,3,1,-1,-3,-5];default:return [5]}};const defaultRange=[[-10,10],[-10,10]];return ys(graph.numSegments).map(y=>{let endpoints=[[-5,y],[5,y]];endpoints=normalizeCoords$1(endpoints,defaultRange);endpoints=normalizePoints(range,step,endpoints);return endpoints})}const defaultLinearCoords=[[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]];function getLineCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}return normalizePoints(range,step,defaultLinearCoords[0])}function getVectorCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}return normalizePoints(range,step,[[.6,.6],[.85,.85]])}function getLinearSystemCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}return defaultLinearCoords.map(points=>normalizePoints(range,step,points))}function getPolygonCoords(graph,range,step){let coords=graph.coords?.slice();if(coords){return coords}const startCoords=graph.startCoords?.slice();if(startCoords){return startCoords}const n=graph.numSides||3;if(n==="unlimited"){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=[...Array(n).keys()].map(i=>[radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]);}coords=normalizeCoords$1(coords,[[-10,10],[-10,10]]);const snapToGrid=!["angles","sides"].includes(graph.snapTo||"");coords=normalizePoints(range,step,coords,!snapToGrid);return coords}function getSinusoidCoords(graph,range,step){if(graph.coords){return [graph.coords[0],graph.coords[1]]}if(graph.startCoords){return [graph.startCoords[0],graph.startCoords[1]]}let coords=[[.5,.5],[.65,.6]];coords=normalizePoints(range,step,coords,true);return coords}function getAbsoluteValueCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}const defaultCoords=[[.5,.5],[.75,.75]];return normalizePoints(range,step,defaultCoords,true)}function getTangentCoords(graph,range,step){if(graph.coords){return [graph.coords[0],graph.coords[1]]}if(graph.startCoords){return [graph.startCoords[0],graph.startCoords[1]]}let coords=[[.5,.5],[.75,.75]];coords=normalizePoints(range,step,coords,true);return coords}function getQuadraticCoords(graph,range,step){if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}const defaultCoords=[[.25,.75],[.5,.25],[.75,.75]];return normalizePoints(range,step,defaultCoords,true)}function getCircleCoords(graph){if(graph.center!=null&&graph.radius!=null){return {center:graph.center,radiusPoint:mafs.vec.add(graph.center,[graph.radius,0])}}if(graph.startCoords?.center&&graph.startCoords.radius){return {center:graph.startCoords.center,radiusPoint:mafs.vec.add(graph.startCoords.center,[graph.startCoords.radius,0])}}return {center:[0,0],radiusPoint:[2,0]}}function getExponentialCoords(graph,range,step){if(graph.coords&&graph.asymptote!=null){return {coords:[graph.coords[0],graph.coords[1]],asymptote:graph.asymptote}}let defaultCoords=[[.5,.6],[.75,.75]];defaultCoords=normalizePoints(range,step,defaultCoords,true);const coords=graph.startCoords?graph.startCoords.coords:defaultCoords;const asymptote=graph.startCoords?graph.startCoords.asymptote:0;return {coords,asymptote}}function getLogarithmCoords(graph,range,step){if(graph.coords&&graph.asymptote!=null){return {coords:[graph.coords[0],graph.coords[1]],asymptote:graph.asymptote}}let defaultCoords=[[.6,.55],[.75,.75]];defaultCoords=normalizePoints(range,step,defaultCoords,true);const coords=graph.startCoords?graph.startCoords.coords:defaultCoords;const asymptote=graph.startCoords?graph.startCoords.asymptote:0;return {coords,asymptote}}const getAngleCoords=params=>{const{graph,range,step}=params;if(graph.coords){return graph.coords}if(graph.startCoords){return graph.startCoords}const{snapDegrees,angleOffsetDeg}=graph;const snap=snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(angleOffsetDeg||0)*Math.PI/180;let defaultCoords=[[.85,.5],[.5,.5]];defaultCoords=normalizePoints(range,step,defaultCoords,true);const radius=magnitude$1(vector$1(...defaultCoords));const coords=[...defaultCoords,[0,0]];coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords};
2032
2032
 
2033
2033
  const{getAngleFromVertex,getClockwiseAngle,polar}=kmath.angles;const{angleMeasures,ccw,lawOfCosines,magnitude,polygonSidesIntersect,reverseVector,sign,vector}=kmath.geometry;const{getQuadraticCoefficients: getQuadraticCoefficients$1}=kmath.coefficients;const minDistanceBetweenAngleVertexAndSidePoint=2;function interactiveGraphReducer(state,action){switch(action.type){case REINITIALIZE:return initializeGraphState(action.params);case MOVE_POINT_IN_FIGURE:return doMovePointInFigure(state,action);case MOVE_LINE:return doMoveLine(state,action);case MOVE_ALL:return doMoveAll(state,action);case MOVE_POINT:return doMovePoint(state,action);case MOVE_CENTER:return doMoveCenter(state,action);case MOVE_RADIUS_POINT:return doMoveRadiusPoint(state,action);case CHANGE_SNAP_STEP:return doChangeSnapStep(state,action);case CHANGE_RANGE:return doChangeRange(state,action);case ADD_POINT:return doAddPoint(state,action);case REMOVE_POINT:return doRemovePoint(state,action);case FOCUS_POINT:return doFocusPoint(state,action);case BLUR_POINT:return doBlurPoint(state);case DELETE_INTENT:return doDeleteIntent(state);case CLICK_POINT:return doClickPoint(state,action);case CLOSE_POLYGON:return doClosePolygon(state);case OPEN_POLYGON:return doOpenPolygon(state);case CHANGE_INTERACTION_MODE:return doChangeInteractionMode(state,action);case CHANGE_KEYBOARD_INVITATION_VISIBILITY:return doChangeKeyboardInvitationVisibility(state,action);default:throw new wonderStuffCore.UnreachableCaseError(action)}}function doDeleteIntent(state,action){if(isUnlimitedGraphState(state)){if(state.focusedPointIndex!==null){return doRemovePoint(state,actions.pointGraph.removePoint(state.focusedPointIndex))}}return state}function doFocusPoint(state,action){switch(state.type){case "polygon":case "point":return {...state,focusedPointIndex:action.index};default:return state}}function doBlurPoint(state,action){switch(state.type){case "polygon":case "point":const nextState={...state,showRemovePointButton:false};if(state.interactionMode==="mouse"){nextState.focusedPointIndex=null;}return nextState;default:return state}}function doClickPoint(state,action){if(isUnlimitedGraphState(state)){return {...state,focusedPointIndex:action.index,showRemovePointButton:true}}return state}function doClosePolygon(state){if(isUnlimitedGraphState(state)&&state.type==="polygon"){const noDupedPoints=getArrayWithoutDuplicates(state.coords);return {...state,coords:noDupedPoints,closedPolygon:true}}return state}function doOpenPolygon(state){if(isUnlimitedGraphState(state)&&state.type==="polygon"){return {...state,closedPolygon:false}}return state}function doChangeInteractionMode(state,action){if(isUnlimitedGraphState(state)){const nextKeyboardInvitation=action.mode==="keyboard"?false:state.showKeyboardInteractionInvitation;return {...state,interactionMode:action.mode,showKeyboardInteractionInvitation:nextKeyboardInvitation}}return state}function doChangeKeyboardInvitationVisibility(state,action){if(isUnlimitedGraphState(state)){return {...state,showKeyboardInteractionInvitation:action.shouldShow,hasBeenInteractedWith:true}}return state}function doMovePointInFigure(state,action){switch(state.type){case "segment":case "linear-system":{const newValue=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=updateAtIndex({array:state.coords,index:action.figureIndex,update:tuple=>setAtIndex({array:tuple,index:action.pointIndex,newValue})});const coordsToCheck=newCoords[action.figureIndex];if(coordsOverlap(coordsToCheck)){return state}const sharedAnnouncement={pointIndex:action.pointIndex,pointLabel:resolvePointLabel(state.pointLabels,action.figureIndex*2+action.pointIndex),x:newValue[X],y:newValue[Y]};const stateAnnouncement=state.type==="segment"?{type:"move-segment-point",segmentIndex:action.figureIndex,totalSegments:state.coords.length,...sharedAnnouncement}:{type:"move-linear-system-point",lineIndex:action.figureIndex,...sharedAnnouncement};return {...state,hasBeenInteractedWith:true,coords:newCoords,stateAnnouncement}}case "ray":case "linear":case "vector":{const newValue=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=setAtIndex({array:state.coords,index:action.pointIndex,newValue});if(coordsOverlap(newCoords)){return state}let stateAnnouncement;if(state.type==="ray"){stateAnnouncement={type:"move-ray-point",pointIndex:action.pointIndex,pointLabel:resolvePointLabel(state.pointLabels,action.pointIndex),x:newValue[X],y:newValue[Y]};}else if(state.type==="vector"){stateAnnouncement={type:"move-vector-point",pointIndex:action.pointIndex,x:newValue[X],y:newValue[Y]};}else {stateAnnouncement={type:"move-point",pointLabel:String(resolvePointLabel(state.pointLabels,action.pointIndex)),x:newValue[X],y:newValue[Y]};}return {...state,hasBeenInteractedWith:true,coords:newCoords,stateAnnouncement}}case "circle":throw new Error(`Don't use movePointInFigure for circle graphs. Use moveCenter or moveRadiusPoint.`);case "angle":case "none":case "point":case "polygon":case "quadratic":case "sinusoid":case "absolute-value":case "tangent":case "exponential":case "logarithm":throw new Error(`Don't use movePointInFigure for ${state.type} graphs. Use movePoint instead!`);default:throw new wonderStuffCore.UnreachableCaseError(state)}}function doMoveLine(state,action){const{snapStep,range}=state;const{newStart}=action;switch(state.type){case "segment":case "linear-system":{if(action.itemIndex===undefined){throw new Error("Please provide index of line to move")}const currentLine=state.coords[action.itemIndex];const constrainedLine=constrainShapePreservingMove(currentLine,newStart,{snapStep,range});const newCoords=setAtIndex({array:state.coords,index:action.itemIndex,newValue:constrainedLine});const stateAnnouncement=state.type==="segment"?{type:"move-segment-line",coords:constrainedLine}:{type:"move-linear-system-line",lineIndex:action.itemIndex,coords:constrainedLine};return {...state,type:state.type,hasBeenInteractedWith:true,coords:newCoords,stateAnnouncement}}case "ray":case "linear":case "vector":{const constrainedLine=constrainShapePreservingMove(state.coords,newStart,{snapStep,range});let type;if(state.type==="ray"){type="move-ray-line";}else if(state.type==="vector"){type="move-vector-line";}else {type="move-linear-line";}const stateAnnouncement={type,coords:constrainedLine};return {...state,type:state.type,hasBeenInteractedWith:true,coords:constrainedLine,stateAnnouncement}}default:return state}}function doMoveAll(state,action){const{snapStep,range}=state;const{newStart}=action;switch(state.type){case "polygon":{const useGridSnap=state.snapTo!=="sides"&&state.snapTo!=="angles";const desiredDelta=mafs.vec.sub(newStart,state.coords[0]);const change=getChange(state.coords,desiredDelta,{snapStep:useGridSnap?snapStep:[0,0],range});const newCoords=state.coords.map(point=>useGridSnap?snap(snapStep,mafs.vec.add(point,change)):mafs.vec.add(point,change));return {...state,hasBeenInteractedWith:true,coords:newCoords,stateAnnouncement:{type:"move-polygon",coords:newCoords,pointLabels:state.pointLabels}}}default:return state}}function doMovePoint(state,action){switch(state.type){case "angle":const newState=(()=>{if(action.index===1){const updatedCoords=boundAndSnapAngleVertex(state,action);return {...state,hasBeenInteractedWith:true,coords:updatedCoords}}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundAndSnapAngleEndPoints(action.destination,state,action.index)})}})();if(angleSidePointsTooCloseToVertex(newState)){return state}const resolvedAngleLabel=resolvePointLabel(state.pointLabels,action.index);return {...newState,stateAnnouncement:{type:"move-angle-point",pointIndex:action.index,pointLabel:resolvedAngleLabel,x:newState.coords[action.index][X],y:newState.coords[action.index][Y],angleMeasure:getClockwiseAngle(newState.coords,newState.allowReflexAngles??false)}};case "polygon":let newValue;if(state.snapTo==="sides"){newValue=boundAndSnapToSides(action.destination,state,action.index);}else if(state.snapTo==="angles"){newValue=boundAndSnapToPolygonAngle(action.destination,state,action.index);}else {newValue=boundToEdgeAndSnapToGrid(action.destination,state);}const newCoords=setAtIndex({array:state.coords,index:action.index,newValue:newValue});const polygonSidesCanIntersect=state.numSides==="unlimited"&&!state.closedPolygon;if(!polygonSidesCanIntersect&&polygonSidesIntersect(newCoords)){return state}return {...state,hasBeenInteractedWith:true,coords:newCoords,stateAnnouncement:{type:"move-point",pointLabel:String(resolvePointLabel(state.pointLabels,action.index)),x:newValue[X],y:newValue[Y]}};case "point":{const newCoord=boundToEdgeAndSnapToGrid(action.destination,state);return {...state,hasBeenInteractedWith:true,focusedPointIndex:action.index,coords:setAtIndex({array:state.coords,index:action.index,newValue:newCoord}),stateAnnouncement:{type:"move-point",pointLabel:String(resolvePointLabel(state.pointLabels,action.index)),x:newCoord[X],y:newCoord[Y]}}}case "sinusoid":{const destination=action.destination;const boundDestination=boundToEdgeAndSnapToGrid(destination,state);const newCoords=[...state.coords];newCoords[action.index]=boundDestination;if(newCoords[0][X]===newCoords[1][X]){return state}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-sinusoid-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:newCoords[action.index][X],y:newCoords[action.index][Y],otherY:newCoords[1-action.index][Y]}}}case "exponential":{const boundDestination=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=[...state.coords];newCoords[action.index]=boundDestination;if(newCoords[0][X]===newCoords[1][X]){return state}const expHandle=getAsymptoteHandleCoord("horizontal",state.range,state.asymptote);if(boundDestination[X]===expHandle[X]&&boundDestination[Y]===expHandle[Y]){return state}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-exponential-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:boundDestination[X],y:boundDestination[Y]}}}case "logarithm":{const boundDestination=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=[...state.coords];newCoords[action.index]=boundDestination;if(newCoords[0][X]===newCoords[1][X]){return state}if(newCoords[0][Y]===newCoords[1][Y]){return state}const logHandle=getAsymptoteHandleCoord("vertical",state.range,state.asymptote);if(boundDestination[X]===logHandle[X]&&boundDestination[Y]===logHandle[Y]){return state}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-logarithm-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:boundDestination[X],y:boundDestination[Y]}}}case "absolute-value":{const boundDestination=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=[...state.coords];newCoords[action.index]=boundDestination;if(newCoords[0][X]===newCoords[1][X]){return state}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-absolute-value-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:boundDestination[X],y:boundDestination[Y]}}}case "tangent":{const boundDestination=boundToEdgeAndSnapToGrid(action.destination,state);const newCoords=[...state.coords];newCoords[action.index]=boundDestination;if(newCoords[0][X]===newCoords[1][X]){return state}return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-tangent-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:boundDestination[X],y:boundDestination[Y]}}}case "quadratic":{const newCoords=[...state.coords];const boundDestination=boundToEdgeAndSnapToGrid(action.destination,state);newCoords[action.index]=boundDestination;const QuadraticCoefficients=getQuadraticCoefficients$1(newCoords);if(QuadraticCoefficients===undefined){return state}const vertex=getQuadraticVertex(QuadraticCoefficients);return {...state,hasBeenInteractedWith:true,coords:setAtIndex({array:state.coords,index:action.index,newValue:boundDestination}),stateAnnouncement:{type:"move-quadratic-point",pointIndex:action.index,pointLabel:resolvePointLabel(state.pointLabels,action.index),x:boundDestination[X],y:boundDestination[Y],vertex}}}default:throw new Error("The movePoint action is only for point, quadratic, and polygon graphs")}}function doMoveCenter(state,action){switch(state.type){case "circle":{const constrainedCenter=boundToEdgeAndSnapToGrid(action.destination,state);const newRadiusPoint=[...mafs.vec.add(state.radiusPoint,mafs.vec.sub(constrainedCenter,state.center))];const[xMin,xMax]=state.range[X];const[radX]=newRadiusPoint;if(radX<xMin||radX>xMax){const xJumpDist=(radX-constrainedCenter[X])*2;const possibleNewX=radX-xJumpDist;if(possibleNewX>=xMin&&possibleNewX<=xMax){newRadiusPoint[X]=possibleNewX;}else {return state}}return {...state,hasBeenInteractedWith:true,center:constrainedCenter,radiusPoint:newRadiusPoint,stateAnnouncement:{type:"move-center",x:constrainedCenter[X],y:constrainedCenter[Y]}}}case "exponential":{const newY=boundAndSnapToGrid(action.destination,state)[Y];if(newY===state.asymptote){return state}const expFutureHandle=getAsymptoteHandleCoord("horizontal",state.range,newY);if(state.coords.some(c=>c[X]===expFutureHandle[X]&&c[Y]===expFutureHandle[Y])){return state}return {...state,hasBeenInteractedWith:true,asymptote:newY,stateAnnouncement:{type:"move-exponential-asymptote",asymptoteY:newY}}}case "logarithm":{const newX=boundAndSnapToGrid(action.destination,state)[X];if(newX===state.asymptote){return state}const logFutureHandle=getAsymptoteHandleCoord("vertical",state.range,newX);if(state.coords.some(c=>c[X]===logFutureHandle[X]&&c[Y]===logFutureHandle[Y])){return state}return {...state,hasBeenInteractedWith:true,asymptote:newX,stateAnnouncement:{type:"move-logarithm-asymptote",asymptoteX:newX}}}default:throw new Error("The doMoveCenter action is only for circle, exponential, or logarithm graphs")}}function doMoveRadiusPoint(state,action){switch(state.type){case "circle":{const nextRadiusPoint=boundToEdgeAndSnapToGrid([action.destination[X],state.center[1]],state);if(kmath.vector.equal(nextRadiusPoint,state.center)){return state}return {...state,hasBeenInteractedWith:true,radiusPoint:nextRadiusPoint,stateAnnouncement:{type:"move-radius-point",x:nextRadiusPoint[X],y:nextRadiusPoint[Y],centerX:state.center[X],radius:mafs.vec.dist(state.center,nextRadiusPoint)}}}default:throw new Error("The doMoveRadiusPoint action is only for circle graphs")}}function doChangeSnapStep(state,action){if(___default.default.isEqual(state.snapStep,action.snapStep)){return state}return {...state,snapStep:action.snapStep}}function doChangeRange(state,action){if(___default.default.isEqual(state.range,action.range)){return state}return {...state,range:action.range}}function doAddPoint(state,action){if(!isUnlimitedGraphState(state)){return state}const{snapStep}=state;const snappedPoint=snap(snapStep,action.location);for(const point of state.coords){if(point[X]===snappedPoint[X]&&point[Y]===snappedPoint[Y]){return state}}const newCoords=[...state.coords,snappedPoint];return {...state,hasBeenInteractedWith:true,coords:newCoords,showRemovePointButton:true,focusedPointIndex:newCoords.length-1}}function doRemovePoint(state,action){if(!isUnlimitedGraphState(state)){return state}const nextFocusedPointIndex=state.coords.length>1?state.coords.length-2:null;return {...state,coords:state.coords.filter((_,i)=>i!==action.index),focusedPointIndex:nextFocusedPointIndex,showRemovePointButton:nextFocusedPointIndex!==null?true:false}}const getDeltaVertex=(maxMoves,minMoves,delta)=>{const[deltaX,deltaY]=delta;const maxXMove=Math.min(...maxMoves.map(move=>move[X]));const maxYMove=Math.min(...maxMoves.map(move=>move[Y]));const minXMove=Math.max(...minMoves.map(move=>move[X]));const minYMove=Math.max(...minMoves.map(move=>move[Y]));const dx=clamp(deltaX,minXMove,maxXMove);const dy=clamp(deltaY,minYMove,maxYMove);return [dx,dy]};const getChange=(coords,delta,constraintOpts)=>{const maxMoves=coords.map(point=>maxMove({...constraintOpts,point}));const minMoves=coords.map(point=>minMove({...constraintOpts,point}));const[dx,dy]=getDeltaVertex(maxMoves,minMoves,delta);return [dx,dy]};const constrainShapePreservingMove=(currentLine,newStart,constraintOpts)=>{const desiredDelta=mafs.vec.sub(newStart,currentLine[0]);const change=getChange(currentLine,desiredDelta,constraintOpts);const{snapStep}=constraintOpts;return [snap(snapStep,mafs.vec.add(currentLine[0],change)),snap(snapStep,mafs.vec.add(currentLine[1],change))]};function leq(a,b){return a<b||perseusCore.approximateEqual(a,b)}function boundAndSnapToGrid(point,{snapStep,range}){return snap(snapStep,bound$1({snapStep,range,point}))}function boundAndSnapAngleVertex({range,coords,snapStep},{destination}){const coordsCopy=[...coords];const startingVertex=coordsCopy[1];const insetAmount=mafs.vec.add(snapStep,[minDistanceBetweenAngleVertexAndSidePoint,minDistanceBetweenAngleVertexAndSidePoint]);const newVertex=clampToBox(inset(insetAmount,range),snap(snapStep,destination));const delta=mafs.vec.add(newVertex,reverseVector(startingVertex));const newPoints={};for(const i of [0,2]){const oldPoint=coordsCopy[i];let newPoint=mafs.vec.add(oldPoint,delta);let angle=getAngleFromVertex(newVertex,newPoint);angle*=Math.PI/180;newPoint=constrainToBoundsOnAngle(newPoint,angle,range,snapStep);newPoints[i]=newPoint;}newPoints[1]=newVertex;Object.entries(newPoints).forEach(([i,newPoint])=>{coordsCopy[i]=newPoint;});return coordsCopy}function tooClose(point1,point2,range){const safeDistance=2;const distance=mafs.vec.dist(point1,point2);return distance<safeDistance}function constrainToBoundsOnAngle(point,angle,range,snapStep){const lower=[range[0][0]+snapStep[0],range[1][0]+snapStep[0]];const upper=[range[0][1]-snapStep[1],range[1][1]-snapStep[1]];let result=point;if(result[0]<lower[0]){result=[lower[0],result[1]+(lower[0]-result[0])*Math.tan(angle)];}else if(result[0]>upper[0]){result=[upper[0],result[1]-(result[0]-upper[0])*Math.tan(angle)];}if(result[1]<lower[1]){result=[result[0]+(lower[1]-result[1])/Math.tan(angle),lower[1]];}else if(result[1]>upper[1]){result=[result[0]-(result[1]-upper[1])/Math.tan(angle),upper[1]];}return result}function boundAndSnapAngleEndPoints(destinationPoint,{range,coords,snapDegrees,angleOffsetDeg,snapStep},index){const snap=snapDegrees||1;const offsetDegrees=angleOffsetDeg||0;const coordsCopy=[...coords];const angleRange=[[range[0][0]+snapStep[0],range[0][1]-snapStep[0]],[range[1][0]+snapStep[1],range[1][1]-snapStep[1]]];const boundPoint=bound$1({snapStep:[0,0],range:angleRange,point:destinationPoint});coordsCopy[index]=boundPoint;const vertex=coords[1];let angle=getAngleFromVertex(coordsCopy[index],vertex);angle=Math.round((angle-offsetDegrees)/snap)*snap+offsetDegrees;const minDistance=minDistanceBetweenAngleVertexAndSidePoint+.01;const distance=Math.max(mafs.vec.dist(coordsCopy[index],vertex),minDistance);const snappedValue=mafs.vec.add(vertex,polar(distance,angle));return snappedValue}function angleSidePointsTooCloseToVertex(state){return tooClose(state.coords[0],state.coords[1],state.range)||tooClose(state.coords[2],state.coords[1],state.range)}function boundAndSnapToPolygonAngle(destinationPoint,{range,coords},index){const startingPoint=coords[index];return calculateAngleSnap(destinationPoint,range,coords,index,startingPoint)}function calculateAngleSnap(destinationPoint,range,coords,index,startingPoint){const coordsCopy=[...coords];coordsCopy[index]=bound$1({snapStep:[0,0],range,point:destinationPoint});const angles=angleMeasures(coordsCopy).map(angle=>angle*180/Math.PI);const rel=j=>{return (index+j+coordsCopy.length)%coordsCopy.length};___default.default.each([-1,1],function(j){angles[rel(j)]=Math.round(angles[rel(j)]);});const getAngle=function(a,vertex,b){const angle=getClockwiseAngle([coordsCopy[rel(a)],coordsCopy[rel(vertex)],coordsCopy[rel(b)]]);return angle};const innerAngles=[angles[rel(-1)]-getAngle(-2,-1,1),angles[rel(1)]-getAngle(-1,1,2)];innerAngles[2]=180-(innerAngles[0]+innerAngles[1]);if(innerAngles.some(function(angle){return leq(angle,1)})){return startingPoint}const knownSide=magnitude(vector(coordsCopy[rel(-1)],coordsCopy[rel(1)]));const onLeft=sign(ccw(coordsCopy[rel(-1)],coordsCopy[rel(1)],coordsCopy[index]))===1;const side=Math.sin(innerAngles[1]*Math.PI/180)/Math.sin(innerAngles[2]*Math.PI/180)*knownSide;const outerAngle=getAngleFromVertex(coordsCopy[rel(1)],coordsCopy[rel(-1)]);const offset=polar(side,outerAngle+(onLeft?1:-1)*innerAngles[0]);return kmath.vector.add(coordsCopy[rel(-1)],offset)}function boundAndSnapToSides(destinationPoint,{range,coords},index){const startingPoint=coords[index];return calculateSideSnap(destinationPoint,range,coords,index,startingPoint)}function calculateSideSnap(destinationPoint,range,coords,index,startingPoint){const boundedDestinationPoint=bound$1({snapStep:[0,0],range,point:destinationPoint});const rel=j=>{return (index+j+coords.length)%coords.length};const sides=___default.default.map([[coords[rel(-1)],boundedDestinationPoint],[boundedDestinationPoint,coords[rel(1)]],[coords[rel(-1)],coords[rel(1)]]],function(coords){return magnitude(vector(...coords))});___default.default.each([0,1],function(j){sides[j]=Math.round(sides[j]);});if(leq(sides[1]+sides[2],sides[0])||leq(sides[0]+sides[2],sides[1])||leq(sides[0]+sides[1],sides[2])){return startingPoint}const innerAngle=lawOfCosines(sides[0],sides[2],sides[1]);const outerAngle=getAngleFromVertex(coords[rel(1)],coords[rel(-1)]);const onLeft=sign(ccw(coords[rel(-1)],coords[rel(1)],boundedDestinationPoint))===1;const offset=polar(sides[0],outerAngle+(onLeft?1:-1)*innerAngle);return kmath.vector.add(coords[rel(-1)],offset)}function maxMove({snapStep,range,point}){const topRight=boundToEdgeAndSnapToGrid([Infinity,Infinity],{snapStep,range});return mafs.vec.sub(topRight,point)}function minMove({snapStep,range,point}){const bottomLeft=boundToEdgeAndSnapToGrid([-Infinity,-Infinity],{snapStep,range});return mafs.vec.sub(bottomLeft,point)}const coordsOverlap=coords=>coords.some((coord,i)=>coords.some((c,j)=>i!==j&&kmath.vector.equal(coord,c)));function updateAtIndex(args){const{array,index,update}=args;const newValue=update(array[index]);return setAtIndex({array,index,newValue})}function setAtIndex(args){const{array,index,newValue}=args;const copy=[...array];copy[index]=newValue;return copy}
2034
2034
 
2035
- const{clockwise}=kmath.geometry;const{convertRadiansToDegrees}=kmath.angles;function renderPolygonGraph(state,dispatch,i18n,markings){return {graph:jsxRuntimeExports.jsx(PolygonGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getPolygonGraphDescription(state,i18n,markings)}}const PolygonGraph=props=>{const{dispatch}=props;const{numSides,coords,snapStep,snapTo="grid"}=props.graphState;const graphConfig=useGraphConfig();const polygonRef=React__namespace.useRef(null);const pointsRef=React__namespace.useRef([]);const lastMoveTimeRef=React__namespace.useRef(0);const{range:[x,y]}=graphConfig;const[[left,top]]=useTransformVectorsToPixels([x[0],y[1]]);const dragReferencePoint=coords[0];const constrain=getKeyboardMovementConstraintForPolygon(snapStep,snapTo);const{dragging}=useDraggable({gestureTarget:polygonRef,point:dragReferencePoint,onMove:newStart=>{dispatch(actions.polygon.moveAll(newStart));},constrainKeyboardMovement:constrain});const[hovered,setHovered]=React__namespace.useState(false);const[focusVisible,setFocusVisible]=React__namespace.useState(false);React__namespace.useEffect(()=>{const focusedIndex=props.graphState.focusedPointIndex;if(focusedIndex!=null){pointsRef.current[focusedIndex]?.focus();}},[props.graphState.focusedPointIndex,props.graphState.coords.length,pointsRef]);React__namespace.useEffect(()=>{if(numSides==="unlimited"&&props.graphState.coords.length>2){dispatch(actions.polygon.closePolygon());}},[]);const statefulProps={...props,graphConfig,polygonRef,pointsRef,lastMoveTimeRef,left,top,dragging,points:coords,hovered,setHovered,focusVisible,setFocusVisible};return numSides==="unlimited"?jsxRuntimeExports.jsx(UnlimitedPolygonGraph,{...statefulProps}):jsxRuntimeExports.jsx(LimitedPolygonGraph,{...statefulProps})};const LimitedPolygonGraph=statefulProps=>{const{dispatch,hovered,setHovered,focusVisible,setFocusVisible,graphConfig,polygonRef,lastMoveTimeRef,dragging,points}=statefulProps;const{showAngles,showSides,range,snapTo="grid",snapStep,pointLabels}=statefulProps.graphState;const{disableKeyboardInteraction,interactiveColor}=graphConfig;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const lines=getLines(points);const polygonPointsNumId=id+"-points-num";const polygonPointsId=id+"-points";const{srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints,srPolygonElementsNum}=describePolygonGraph(statefulProps.graphState,{strings,locale},statefulProps.graphConfig.markings);return jsxRuntimeExports.jsxs("g",{"aria-label":srPolygonGraph,"aria-describedby":`${polygonPointsNumId} ${polygonPointsId}`,children:[jsxRuntimeExports.jsx(mafs.Polygon,{points:[...points],color:interactiveColor,svgPolygonProps:{strokeWidth:focusVisible?"var(--movable-line-stroke-weight-active)":"var(--movable-line-stroke-weight)",style:{fill:"transparent"},"aria-hidden":true}}),points.map((point,i)=>{const pt1=points.at(i-1);const pt2=points[(i+1)%points.length];if(!pt1||!pt2){return null}return jsxRuntimeExports.jsx(PolygonAngle,{centerPoint:point,endPoints:[pt1,pt2],areEndPointsClockwise:clockwise(points),showAngles:!!showAngles,snapTo:snapTo},"angle-"+i)}),showSides&&lines.map(([start,end],i)=>{const[x,y]=mafs.vec.midpoint(start,end);const length=mafs.vec.dist(start,end);const isApprox=!Number.isInteger(length);return jsxRuntimeExports.jsx(TextLabel,{x:x,y:y,children:isApprox?`≈ ${length.toFixed(snapTo==="sides"?0:1)}`:length},"side-"+i)}),jsxRuntimeExports.jsx(mafs.Polygon,{points:[...points],color:"transparent",svgPolygonProps:{ref:polygonRef,tabIndex:disableKeyboardInteraction?-1:0,strokeWidth:TARGET_SIZE,style:{cursor:dragging?"grabbing":"grab",fill:hovered?"var(--mafs-blue)":"transparent"},onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),onKeyDownCapture:()=>{setFocusVisible(hasFocusVisible(polygonRef.current));},onFocus:()=>{setFocusVisible(hasFocusVisible(polygonRef.current));},onBlur:()=>setFocusVisible(hasFocusVisible(polygonRef.current)),className:"movable-polygon",role:"button","aria-label":srPolygonGraphPoints?`${srPolygonElementsNum} ${srPolygonGraphPoints}`:srPolygonElementsNum,"aria-disabled":disableKeyboardInteraction}}),points.map((point,i)=>{const angleId=`${id}-angle-${i}`;const side1Id=`${id}-point-${i}-side-1`;const side2Id=`${id}-point-${i}-side-2`;const angle=getAngleFromPoints(points,i);const angleDegree=angle?convertRadiansToDegrees(angle):null;const sidesArray=getSideLengthsFromPoints(points,i);const{pointIndex:point1Index,sideLength:side1Length}=sidesArray[0];const{pointIndex:point2Index,sideLength:side2Length}=sidesArray[1];return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(MovablePoint$1,{ariaDescribedBy:`${angleId} ${side1Id} ${side2Id}`,ariaLabel:buildLabel(i,point),ariaLive:"off",constrain:getKeyboardMovementConstraintForPoint(points,i,range,snapStep,snapTo),point:point,sequenceNumber:i+1,onMove:destination=>{const now=Date.now();const targetFPS=40;const moveThresholdTime=1e3/targetFPS;if(now-lastMoveTimeRef.current>moveThresholdTime){dispatch(actions.polygon.movePoint(i,destination));lastMoveTimeRef.current=now;}}}),angleDegree&&jsxRuntimeExports.jsx(SRDescInSVG,{id:angleId,children:Number.isInteger(angleDegree)?strings.srPolygonPointAngle({angle:angleDegree}):strings.srPolygonPointAngleApprox({angle:srFormatNumber(angleDegree,locale,1)})}),jsxRuntimeExports.jsx(SRDescInSVG,{id:side1Id,children:getPolygonSideString(side1Length,point1Index,strings,locale)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:side2Id,children:getPolygonSideString(side2Length,point2Index,strings,locale)})]},"point-"+i)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsNumId,children:srPolygonGraphPointsNum}),srPolygonGraphPoints&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsId,children:srPolygonGraphPoints})]})};const UnlimitedPolygonGraph=statefulProps=>{const{dispatch,graphConfig,left,top,pointsRef,points}=statefulProps;const{coords,closedPolygon,pointLabels}=statefulProps.graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const{interactiveColor}=useGraphConfig();const[isCurrentlyDragging,setIsCurrentlyDragging]=React.useState(false);const dragEndCallbackTimer=wonderBlocksTiming.useTimeout(()=>setIsCurrentlyDragging(false),400);const id=React__namespace.useId();const polygonPointsNumId=id+"-points-num";const polygonPointsId=id+"-points";if(closedPolygon){const closedPolygonProps={...statefulProps,numSides:coords.length};return jsxRuntimeExports.jsx(LimitedPolygonGraph,{...closedPolygonProps})}const{graphDimensionsInPixels}=graphConfig;const widthPx=graphDimensionsInPixels[0];const heightPx=graphDimensionsInPixels[1];const emptyGraph=coords.length===0;const{srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints}=describePolygonGraph(statefulProps.graphState,{strings,locale},statefulProps.graphConfig.markings);return jsxRuntimeExports.jsxs("g",{"aria-label":emptyGraph?strings.srUnlimitedPolygonEmpty:srPolygonGraph,"aria-describedby":`${polygonPointsNumId} ${polygonPointsId}`,children:[jsxRuntimeExports.jsx(mafs.Polyline,{points:[...points],color:interactiveColor,svgPolylineProps:{strokeWidth:"var(--movable-line-stroke-weight)",style:{fill:"transparent"},"aria-hidden":true}}),jsxRuntimeExports.jsx("rect",{"aria-hidden":true,style:{fill:"rgba(0,0,0,0)",cursor:"crosshair"},width:widthPx,height:heightPx,x:left,y:top,onClick:event=>{if(isCurrentlyDragging){return}const elementRect=event.currentTarget.getBoundingClientRect();const zoomFactor=getCSSZoomFactor(event.currentTarget);const x=(event.clientX-elementRect.x)/zoomFactor;const y=(event.clientY-elementRect.y)/zoomFactor;const graphCoordinates=pixelsToVectors([[x,y]],graphConfig);dispatch(actions.polygon.addPoint(graphCoordinates[0]));}}),coords.map((point,i)=>{const angleId=`${id}-angle-${i}`;let sideIds="";const hasAngle=i>0&&i<coords.length-1;const angle=hasAngle?getAngleFromPoints(points,i):null;const angleDegree=angle?convertRadiansToDegrees(angle):null;const sidesArray=getSideLengthsFromPoints(points,i,true);for(let sideIndex=0;sideIndex<sidesArray.length;sideIndex++){sideIds+=`${id}-point-${i}-side-${sideIndex} `;}return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(MovablePoint$1,{ariaDescribedBy:`${angleId} ${sideIds}`,ariaLabel:buildLabel(i,point),ariaLive:"off",point:point,sequenceNumber:i+1,onDragStart:()=>{dragEndCallbackTimer.clear();setIsCurrentlyDragging(true);},onMove:destination=>{dispatch(actions.polygon.movePoint(i,destination));},onDragEnd:()=>{dragEndCallbackTimer.set();},ref:ref=>{pointsRef.current[i]=ref;},onFocus:()=>{dispatch(actions.polygon.focusPoint(i));},onClick:()=>{if(i===0&&getArrayWithoutDuplicates(coords).length>=3){dispatch(actions.polygon.closePolygon());}dispatch(actions.polygon.clickPoint(i));}}),angleDegree&&jsxRuntimeExports.jsx(SRDescInSVG,{id:angleId,children:Number.isInteger(angleDegree)?strings.srPolygonPointAngle({angle:angleDegree}):strings.srPolygonPointAngleApprox({angle:srFormatNumber(angleDegree,locale,1)})}),sidesArray.map(({pointIndex,sideLength},j)=>jsxRuntimeExports.jsx(SRDescInSVG,{id:`${id}-point-${i}-side-${j}`,children:getPolygonSideString(sideLength,pointIndex,strings,locale)},`${id}-point-${i}-side-${j}`))]},"point-"+i)}),coords.length>0&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsNumId,children:srPolygonGraphPointsNum}),srPolygonGraphPoints&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsId,children:srPolygonGraphPoints})]})};function getLines(points){return points.map((point,i)=>{const next=points[(i+1)%points.length];return [point,next]})}const hasFocusVisible=element=>{const matches=selector=>element?.matches(selector)??false;try{return matches(":focus-visible")}catch{return matches(":focus")}};function getPolygonGraphDescription(state,i18n,markings){const strings=describePolygonGraph(state,i18n,markings);return strings.srPolygonInteractiveElements}function describePolygonGraph(state,i18n,markings){const{strings,locale}=i18n;const{coords,pointLabels}=state;const buildLabel=(index,point)=>buildPointAriaLabel(pointLabels,index,point,strings,locale);const isCoordinatePlane=markings==="axes"||markings==="graph";const hasOnePoint=coords.length===1;const srPolygonGraph=isCoordinatePlane?strings.srPolygonGraphCoordinatePlane:strings.srPolygonGraph;const srPolygonGraphPointsNum=hasOnePoint?strings.srPolygonGraphPointsOne:strings.srPolygonGraphPointsNum({num:coords.length});let srPolygonGraphPoints;if(isCoordinatePlane){const pointsString=coords.map((coord,i)=>buildLabel(i,coord)??strings.srPointAtCoordinates({num:i+1,x:srFormatNumber(coord[0],locale),y:srFormatNumber(coord[1],locale)}));srPolygonGraphPoints=pointsString.join(" ");}const srPolygonElementsNum=hasOnePoint?strings.srPolygonElementsOne:strings.srPolygonElementsNum({num:coords.length});const srPolygonInteractiveElements=coords.length>0?strings.srInteractiveElements({elements:[srPolygonElementsNum,srPolygonGraphPoints].join(" ")}):null;return {srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints,srPolygonElementsNum,srPolygonInteractiveElements}}function getKeyboardMovementConstraintForPoint(points,index,range,snapStep,snapTo){switch(snapTo){case "grid":return p=>snap(snapStep,p);case "sides":return getSideSnapConstraint(points,index,range);case "angles":return getAngleSnapConstraint(points,index,range);default:throw new wonderStuffCore.UnreachableCaseError(snapTo)}}function getKeyboardMovementConstraintForPolygon(snapStep,snapTo){switch(snapTo){case "grid":return p=>snap(snapStep,p);case "sides":case "angles":return p=>p;default:throw new wonderStuffCore.UnreachableCaseError(snapTo)}}function getSideSnapConstraint(points,index,range){const newPoints=[...points];const pointToBeMoved=newPoints[index];const movePointWithConstraint=moveFunc=>{let destinationAttempt=moveFunc(pointToBeMoved);let newPoint=pointToBeMoved;while(newPoint[0]===pointToBeMoved[0]&&newPoint[1]===pointToBeMoved[1]&&isInBound({range,point:destinationAttempt})){newPoint=calculateSideSnap(destinationAttempt,range,newPoints,index,pointToBeMoved);destinationAttempt=moveFunc(destinationAttempt);}return newPoint};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,1])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,1])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[1,0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[1,0]))}}function getAngleSnapConstraint(points,index,range){const newPoints=[...points];const pointToBeMoved=newPoints[index];const movePointWithConstraint=moveFunc=>{let destinationAttempt=bound$1({snapStep:[0,0],range,point:moveFunc(pointToBeMoved)});let newPoint=pointToBeMoved;while(newPoint[0]===pointToBeMoved[0]&&newPoint[1]===pointToBeMoved[1]&&isInBound({range,point:destinationAttempt})){newPoint=calculateAngleSnap(destinationAttempt,range,newPoints,index,pointToBeMoved);destinationAttempt=moveFunc(destinationAttempt);}return newPoint};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,.1])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,.1])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[.1,0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[.1,0]))}}
2035
+ const{clockwise}=kmath.geometry;const{convertRadiansToDegrees}=kmath.angles;function renderPolygonGraph(state,dispatch,i18n,markings){return {graph:jsxRuntimeExports.jsx(PolygonGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getPolygonGraphDescription(state,i18n,markings)}}const PolygonGraph=props=>{const{dispatch}=props;const{numSides,coords,snapStep,snapTo="grid"}=props.graphState;const graphConfig=useGraphConfig();const polygonRef=React__namespace.useRef(null);const pointsRef=React__namespace.useRef([]);const lastMoveTimeRef=React__namespace.useRef(0);const{range:[x,y]}=graphConfig;const[[left,top]]=useTransformVectorsToPixels([x[0],y[1]]);const dragReferencePoint=coords[0];const constrain=getKeyboardMovementConstraintForPolygon(snapStep,snapTo);const{dragging}=useDraggable({gestureTarget:polygonRef,point:dragReferencePoint,onMove:newStart=>{dispatch(actions.polygon.moveAll(newStart));},constrainKeyboardMovement:constrain});const[hovered,setHovered]=React__namespace.useState(false);const[focusVisible,setFocusVisible]=React__namespace.useState(false);React__namespace.useEffect(()=>{const focusedIndex=props.graphState.focusedPointIndex;if(focusedIndex!=null){pointsRef.current[focusedIndex]?.focus();}},[props.graphState.focusedPointIndex,props.graphState.coords.length,pointsRef]);React__namespace.useEffect(()=>{if(numSides==="unlimited"&&props.graphState.coords.length>2){dispatch(actions.polygon.closePolygon());}},[]);const statefulProps={...props,graphConfig,polygonRef,pointsRef,lastMoveTimeRef,left,top,dragging,points:coords,hovered,setHovered,focusVisible,setFocusVisible};return numSides==="unlimited"?jsxRuntimeExports.jsx(UnlimitedPolygonGraph,{...statefulProps}):jsxRuntimeExports.jsx(LimitedPolygonGraph,{...statefulProps})};const LimitedPolygonGraph=statefulProps=>{const{dispatch,hovered,setHovered,focusVisible,setFocusVisible,graphConfig,polygonRef,lastMoveTimeRef,dragging,points}=statefulProps;const{showAngles,showSides,range,snapTo="grid",snapStep,pointLabels}=statefulProps.graphState;const{disableKeyboardInteraction,interactiveColor}=graphConfig;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const lines=getLines(points);const polygonPointsNumId=id+"-points-num";const polygonPointsId=id+"-points";const{srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints,srPolygonElementsNum}=describePolygonGraph(statefulProps.graphState,{strings,locale},statefulProps.graphConfig.markings);return jsxRuntimeExports.jsxs("g",{"aria-label":srPolygonGraph,"aria-describedby":`${polygonPointsNumId} ${polygonPointsId}`,children:[jsxRuntimeExports.jsx(mafs.Polygon,{points:[...points],color:interactiveColor,svgPolygonProps:{strokeWidth:focusVisible?"var(--movable-line-stroke-weight-active)":"var(--movable-line-stroke-weight)",style:{fill:"transparent"},"aria-hidden":true}}),points.map((point,i)=>{const pt1=points.at(i-1);const pt2=points[(i+1)%points.length];if(!pt1||!pt2){return null}return jsxRuntimeExports.jsx(PolygonAngle,{centerPoint:point,endPoints:[pt1,pt2],areEndPointsClockwise:clockwise(points),showAngles:!!showAngles,snapTo:snapTo},"angle-"+i)}),showSides&&lines.map(([start,end],i)=>{const[x,y]=mafs.vec.midpoint(start,end);const length=mafs.vec.dist(start,end);const isApprox=!Number.isInteger(length);return jsxRuntimeExports.jsx(TextLabel,{x:x,y:y,children:isApprox?`≈ ${length.toFixed(snapTo==="sides"?0:1)}`:length},"side-"+i)}),jsxRuntimeExports.jsx(mafs.Polygon,{points:[...points],color:"transparent",svgPolygonProps:{ref:polygonRef,tabIndex:disableKeyboardInteraction?-1:0,strokeWidth:TARGET_SIZE,style:{cursor:dragging?"grabbing":"grab",fill:hovered?"var(--mafs-blue)":"transparent"},onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),onKeyDownCapture:()=>{setFocusVisible(hasFocusVisible(polygonRef.current));},onFocus:()=>{setFocusVisible(hasFocusVisible(polygonRef.current));},onBlur:()=>setFocusVisible(hasFocusVisible(polygonRef.current)),className:"movable-polygon",role:"button","aria-label":srPolygonGraphPoints?`${srPolygonElementsNum} ${srPolygonGraphPoints}`:srPolygonElementsNum,"aria-disabled":disableKeyboardInteraction}}),points.map((point,i)=>{const angleId=`${id}-angle-${i}`;const side1Id=`${id}-point-${i}-side-1`;const side2Id=`${id}-point-${i}-side-2`;const angle=getAngleFromPoints(points,i);const angleDegree=angle?convertRadiansToDegrees(angle):null;const sidesArray=getSideLengthsFromPoints(points,i);const{pointIndex:point1Index,sideLength:side1Length}=sidesArray[0];const{pointIndex:point2Index,sideLength:side2Length}=sidesArray[1];return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(MovablePoint$1,{ariaDescribedBy:`${angleId} ${side1Id} ${side2Id}`,ariaLabel:buildLabel(i,point),constrain:getKeyboardMovementConstraintForPoint(points,i,range,snapStep,snapTo),point:point,sequenceNumber:i+1,onMove:destination=>{const now=Date.now();const targetFPS=40;const moveThresholdTime=1e3/targetFPS;if(now-lastMoveTimeRef.current>moveThresholdTime){dispatch(actions.polygon.movePoint(i,destination));lastMoveTimeRef.current=now;}}}),angleDegree&&jsxRuntimeExports.jsx(SRDescInSVG,{id:angleId,children:Number.isInteger(angleDegree)?strings.srPolygonPointAngle({angle:angleDegree}):strings.srPolygonPointAngleApprox({angle:srFormatNumber(angleDegree,locale,1)})}),jsxRuntimeExports.jsx(SRDescInSVG,{id:side1Id,children:getPolygonSideString(side1Length,point1Index,strings,locale)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:side2Id,children:getPolygonSideString(side2Length,point2Index,strings,locale)})]},"point-"+i)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsNumId,children:srPolygonGraphPointsNum}),srPolygonGraphPoints&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsId,children:srPolygonGraphPoints})]})};const UnlimitedPolygonGraph=statefulProps=>{const{dispatch,graphConfig,left,top,pointsRef,points}=statefulProps;const{coords,closedPolygon,pointLabels}=statefulProps.graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const{interactiveColor}=useGraphConfig();const[isCurrentlyDragging,setIsCurrentlyDragging]=React.useState(false);const dragEndCallbackTimer=wonderBlocksTiming.useTimeout(()=>setIsCurrentlyDragging(false),400);const id=React__namespace.useId();const polygonPointsNumId=id+"-points-num";const polygonPointsId=id+"-points";if(closedPolygon){const closedPolygonProps={...statefulProps,numSides:coords.length};return jsxRuntimeExports.jsx(LimitedPolygonGraph,{...closedPolygonProps})}const{graphDimensionsInPixels}=graphConfig;const widthPx=graphDimensionsInPixels[0];const heightPx=graphDimensionsInPixels[1];const emptyGraph=coords.length===0;const{srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints}=describePolygonGraph(statefulProps.graphState,{strings,locale},statefulProps.graphConfig.markings);return jsxRuntimeExports.jsxs("g",{"aria-label":emptyGraph?strings.srUnlimitedPolygonEmpty:srPolygonGraph,"aria-describedby":`${polygonPointsNumId} ${polygonPointsId}`,children:[jsxRuntimeExports.jsx(mafs.Polyline,{points:[...points],color:interactiveColor,svgPolylineProps:{strokeWidth:"var(--movable-line-stroke-weight)",style:{fill:"transparent"},"aria-hidden":true}}),jsxRuntimeExports.jsx("rect",{"aria-hidden":true,style:{fill:"rgba(0,0,0,0)",cursor:"crosshair"},width:widthPx,height:heightPx,x:left,y:top,onClick:event=>{if(isCurrentlyDragging){return}const elementRect=event.currentTarget.getBoundingClientRect();const zoomFactor=getCSSZoomFactor(event.currentTarget);const x=(event.clientX-elementRect.x)/zoomFactor;const y=(event.clientY-elementRect.y)/zoomFactor;const graphCoordinates=pixelsToVectors([[x,y]],graphConfig);dispatch(actions.polygon.addPoint(graphCoordinates[0]));}}),coords.map((point,i)=>{const angleId=`${id}-angle-${i}`;let sideIds="";const hasAngle=i>0&&i<coords.length-1;const angle=hasAngle?getAngleFromPoints(points,i):null;const angleDegree=angle?convertRadiansToDegrees(angle):null;const sidesArray=getSideLengthsFromPoints(points,i,true);for(let sideIndex=0;sideIndex<sidesArray.length;sideIndex++){sideIds+=`${id}-point-${i}-side-${sideIndex} `;}return jsxRuntimeExports.jsxs("g",{children:[jsxRuntimeExports.jsx(MovablePoint$1,{ariaDescribedBy:`${angleId} ${sideIds}`,ariaLabel:buildLabel(i,point),point:point,sequenceNumber:i+1,onDragStart:()=>{dragEndCallbackTimer.clear();setIsCurrentlyDragging(true);},onMove:destination=>{dispatch(actions.polygon.movePoint(i,destination));},onDragEnd:()=>{dragEndCallbackTimer.set();},ref:ref=>{pointsRef.current[i]=ref;},onFocus:()=>{dispatch(actions.polygon.focusPoint(i));},onClick:()=>{if(i===0&&getArrayWithoutDuplicates(coords).length>=3){dispatch(actions.polygon.closePolygon());}dispatch(actions.polygon.clickPoint(i));}}),angleDegree&&jsxRuntimeExports.jsx(SRDescInSVG,{id:angleId,children:Number.isInteger(angleDegree)?strings.srPolygonPointAngle({angle:angleDegree}):strings.srPolygonPointAngleApprox({angle:srFormatNumber(angleDegree,locale,1)})}),sidesArray.map(({pointIndex,sideLength},j)=>jsxRuntimeExports.jsx(SRDescInSVG,{id:`${id}-point-${i}-side-${j}`,children:getPolygonSideString(sideLength,pointIndex,strings,locale)},`${id}-point-${i}-side-${j}`))]},"point-"+i)}),coords.length>0&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsNumId,children:srPolygonGraphPointsNum}),srPolygonGraphPoints&&jsxRuntimeExports.jsx(SRDescInSVG,{id:polygonPointsId,children:srPolygonGraphPoints})]})};function getLines(points){return points.map((point,i)=>{const next=points[(i+1)%points.length];return [point,next]})}const hasFocusVisible=element=>{const matches=selector=>element?.matches(selector)??false;try{return matches(":focus-visible")}catch{return matches(":focus")}};function getPolygonGraphDescription(state,i18n,markings){const strings=describePolygonGraph(state,i18n,markings);return strings.srPolygonInteractiveElements}function describePolygonGraph(state,i18n,markings){const{strings,locale}=i18n;const{coords,pointLabels}=state;const buildLabel=(index,point)=>buildPointAriaLabel(pointLabels,index,point,strings,locale);const isCoordinatePlane=markings==="axes"||markings==="graph";const hasOnePoint=coords.length===1;const srPolygonGraph=isCoordinatePlane?strings.srPolygonGraphCoordinatePlane:strings.srPolygonGraph;const srPolygonGraphPointsNum=hasOnePoint?strings.srPolygonGraphPointsOne:strings.srPolygonGraphPointsNum({num:coords.length});let srPolygonGraphPoints;if(isCoordinatePlane){const pointsString=coords.map((coord,i)=>buildLabel(i,coord)??strings.srPointAtCoordinates({num:i+1,x:srFormatNumber(coord[0],locale),y:srFormatNumber(coord[1],locale)}));srPolygonGraphPoints=pointsString.join(" ");}const srPolygonElementsNum=hasOnePoint?strings.srPolygonElementsOne:strings.srPolygonElementsNum({num:coords.length});const srPolygonInteractiveElements=coords.length>0?strings.srInteractiveElements({elements:[srPolygonElementsNum,srPolygonGraphPoints].join(" ")}):null;return {srPolygonGraph,srPolygonGraphPointsNum,srPolygonGraphPoints,srPolygonElementsNum,srPolygonInteractiveElements}}function getKeyboardMovementConstraintForPoint(points,index,range,snapStep,snapTo){switch(snapTo){case "grid":return p=>snap(snapStep,p);case "sides":return getSideSnapConstraint(points,index,range);case "angles":return getAngleSnapConstraint(points,index,range);default:throw new wonderStuffCore.UnreachableCaseError(snapTo)}}function getKeyboardMovementConstraintForPolygon(snapStep,snapTo){switch(snapTo){case "grid":return p=>snap(snapStep,p);case "sides":case "angles":return p=>p;default:throw new wonderStuffCore.UnreachableCaseError(snapTo)}}function getSideSnapConstraint(points,index,range){const newPoints=[...points];const pointToBeMoved=newPoints[index];const movePointWithConstraint=moveFunc=>{let destinationAttempt=moveFunc(pointToBeMoved);let newPoint=pointToBeMoved;while(newPoint[0]===pointToBeMoved[0]&&newPoint[1]===pointToBeMoved[1]&&isInBound({range,point:destinationAttempt})){newPoint=calculateSideSnap(destinationAttempt,range,newPoints,index,pointToBeMoved);destinationAttempt=moveFunc(destinationAttempt);}return newPoint};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,1])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,1])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[1,0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[1,0]))}}function getAngleSnapConstraint(points,index,range){const newPoints=[...points];const pointToBeMoved=newPoints[index];const movePointWithConstraint=moveFunc=>{let destinationAttempt=bound$1({snapStep:[0,0],range,point:moveFunc(pointToBeMoved)});let newPoint=pointToBeMoved;while(newPoint[0]===pointToBeMoved[0]&&newPoint[1]===pointToBeMoved[1]&&isInBound({range,point:destinationAttempt})){newPoint=calculateAngleSnap(destinationAttempt,range,newPoints,index,pointToBeMoved);destinationAttempt=moveFunc(destinationAttempt);}return newPoint};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,.1])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,.1])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[.1,0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[.1,0]))}}
2036
2036
 
2037
- function renderQuadraticGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(QuadraticGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getQuadraticGraphDescription(state,i18n)}}function QuadraticGraph(props){const{dispatch,graphState}=props;const{coords,pointLabels,snapStep}=graphState;const{interactiveColor}=useGraphConfig();const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const quadraticDirectionId=id+"-direction";const quadraticVertexId=id+"-vertex";const quadraticInterceptsId=id+"-intercepts";const coeffRef=React__namespace.useRef([0,0,0]);const coeffs=getQuadraticCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const[a,b,c]=coeffRef.current;const y=x=>(a*x+b)*x+c;const{srQuadraticGraph,srQuadraticDirection,srQuadraticVertex,srQuadraticXIntercepts,srQuadraticYIntercept}=describeQuadraticGraph(graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srQuadraticGraph,"aria-describedby":`${quadraticDirectionId} ${quadraticVertexId} ${quadraticInterceptsId}`,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:y,color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>{const srQuadraticPoint=getQuadraticPointString(i+1,coord,strings,locale);const srVertex=srQuadraticVertex?` ${srQuadraticVertex}`:"";return jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??`${srQuadraticPoint}${srVertex}`,point:coord,sequenceNumber:i+1,constrain:getQuadraticKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.quadratic.movePoint(i,destination)),ariaLive:"off"},"point-"+i)}),srQuadraticDirection&&jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticDirectionId,children:srQuadraticDirection}),srQuadraticVertex&&jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticVertexId,children:srQuadraticVertex}),jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticInterceptsId,children:srQuadraticXIntercepts?`${srQuadraticXIntercepts} ${srQuadraticYIntercept}`:`${srQuadraticYIntercept}`})]})}const getQuadraticCoefficients=coords=>{const p1=coords[0];const p2=coords[1];const p3=coords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return}const a=(p3[0]*(p2[1]-p1[1])+p2[0]*(p1[1]-p3[1])+p1[0]*(p3[1]-p2[1]))/denom;const b=(p3[0]*p3[0]*(p1[1]-p2[1])+p2[0]*p2[0]*(p3[1]-p1[1])+p1[0]*p1[0]*(p2[1]-p3[1]))/denom;const c=(p2[0]*p3[0]*(p2[0]-p3[0])*p1[1]+p3[0]*p1[0]*(p3[0]-p1[0])*p2[1]+p1[0]*p2[0]*(p1[0]-p2[0])*p3[1])/denom;return [a,b,c]};function getQuadraticGraphDescription(state,i18n){const strings=describeQuadraticGraph(state,i18n);return strings.srQuadraticInteractiveElements}function describeQuadraticGraph(state,i18n){const{strings,locale}=i18n;const coeffs=getQuadraticCoefficients(state.coords);const[a,b,c]=coeffs??[0,0,0];const vertex=getQuadraticVertex([a,b,c]);const xIntercepts=getQuadraticXIntercepts(a,b,c);const srQuadraticGraph=strings.srQuadraticGraph;const srQuadraticFaceUp=strings.srQuadraticFaceUp;const srQuadraticFaceDown=strings.srQuadraticFaceDown;const srQuadraticDirection=a===0?undefined:a>0?srQuadraticFaceUp:srQuadraticFaceDown;const srQuadraticVertex=vertex===undefined?undefined:getQuadraticVertexString(vertex,strings);const srQuadraticXIntercepts=xIntercepts.length===2?strings.srQuadraticTwoXIntercepts({intercept1:srFormatNumber(xIntercepts[0],locale),intercept2:srFormatNumber(xIntercepts[1],locale)}):xIntercepts.length===1?strings.srQuadraticOneXIntercept({intercept:srFormatNumber(xIntercepts[0],locale)}):undefined;const srQuadraticYIntercept=strings.srQuadraticYIntercept({intercept:srFormatNumber(c,locale)});const srQuadraticInteractiveElements=strings.srInteractiveElements({elements:strings.srQuadraticInteractiveElements({point1X:srFormatNumber(state.coords[0][0],locale),point1Y:srFormatNumber(state.coords[0][1],locale),point2X:srFormatNumber(state.coords[1][0],locale),point2Y:srFormatNumber(state.coords[1][1],locale),point3X:srFormatNumber(state.coords[2][0],locale),point3Y:srFormatNumber(state.coords[2][1],locale)})});return {srQuadraticGraph,srQuadraticDirection,srQuadraticVertex,srQuadraticXIntercepts,srQuadraticYIntercept,srQuadraticInteractiveElements}}const getQuadraticKeyboardConstraint=(coords,snapStep,pointMoved)=>{const newCoords=[coords[0],coords[1],coords[2]];const coordToBeMoved=newCoords[pointMoved];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);newCoords[pointMoved]=movedCoord;if(areCoordsValid(newCoords)){return movedCoord}movedCoord=moveFunc(movedCoord);newCoords[pointMoved]=movedCoord;if(areCoordsValid(newCoords)){return movedCoord}return moveFunc(movedCoord)};return {up:mafs.vec.add(coordToBeMoved,[0,snapStep[1]]),down:mafs.vec.sub(coordToBeMoved,[0,snapStep[1]]),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const areCoordsValid=coords=>{const p1=coords[0];const p2=coords[1];const p3=coords[2];if(p1[0]===p2[0]||p2[0]===p3[0]||p1[0]===p3[0]){return false}return true};
2037
+ function renderQuadraticGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(QuadraticGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getQuadraticGraphDescription(state,i18n)}}function QuadraticGraph(props){const{dispatch,graphState}=props;const{coords,pointLabels,snapStep}=graphState;const{interactiveColor}=useGraphConfig();const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const quadraticDirectionId=id+"-direction";const quadraticVertexId=id+"-vertex";const quadraticInterceptsId=id+"-intercepts";const coeffRef=React__namespace.useRef([0,0,0]);const coeffs=getQuadraticCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const[a,b,c]=coeffRef.current;const y=x=>(a*x+b)*x+c;const{srQuadraticGraph,srQuadraticDirection,srQuadraticVertex,srQuadraticXIntercepts,srQuadraticYIntercept}=describeQuadraticGraph(graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srQuadraticGraph,"aria-describedby":`${quadraticDirectionId} ${quadraticVertexId} ${quadraticInterceptsId}`,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:y,color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>{const srQuadraticPoint=getQuadraticPointString(i+1,coord,strings,locale);const srVertex=srQuadraticVertex?` ${srQuadraticVertex}`:"";return jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??`${srQuadraticPoint}${srVertex}`,point:coord,sequenceNumber:i+1,constrain:getQuadraticKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.quadratic.movePoint(i,destination))},"point-"+i)}),srQuadraticDirection&&jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticDirectionId,children:srQuadraticDirection}),srQuadraticVertex&&jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticVertexId,children:srQuadraticVertex}),jsxRuntimeExports.jsx(SRDescInSVG,{id:quadraticInterceptsId,children:srQuadraticXIntercepts?`${srQuadraticXIntercepts} ${srQuadraticYIntercept}`:`${srQuadraticYIntercept}`})]})}const getQuadraticCoefficients=coords=>{const p1=coords[0];const p2=coords[1];const p3=coords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return}const a=(p3[0]*(p2[1]-p1[1])+p2[0]*(p1[1]-p3[1])+p1[0]*(p3[1]-p2[1]))/denom;const b=(p3[0]*p3[0]*(p1[1]-p2[1])+p2[0]*p2[0]*(p3[1]-p1[1])+p1[0]*p1[0]*(p2[1]-p3[1]))/denom;const c=(p2[0]*p3[0]*(p2[0]-p3[0])*p1[1]+p3[0]*p1[0]*(p3[0]-p1[0])*p2[1]+p1[0]*p2[0]*(p1[0]-p2[0])*p3[1])/denom;return [a,b,c]};function getQuadraticGraphDescription(state,i18n){const strings=describeQuadraticGraph(state,i18n);return strings.srQuadraticInteractiveElements}function describeQuadraticGraph(state,i18n){const{strings,locale}=i18n;const coeffs=getQuadraticCoefficients(state.coords);const[a,b,c]=coeffs??[0,0,0];const vertex=getQuadraticVertex([a,b,c]);const xIntercepts=getQuadraticXIntercepts(a,b,c);const srQuadraticGraph=strings.srQuadraticGraph;const srQuadraticFaceUp=strings.srQuadraticFaceUp;const srQuadraticFaceDown=strings.srQuadraticFaceDown;const srQuadraticDirection=a===0?undefined:a>0?srQuadraticFaceUp:srQuadraticFaceDown;const srQuadraticVertex=vertex===undefined?undefined:getQuadraticVertexString(vertex,strings);const srQuadraticXIntercepts=xIntercepts.length===2?strings.srQuadraticTwoXIntercepts({intercept1:srFormatNumber(xIntercepts[0],locale),intercept2:srFormatNumber(xIntercepts[1],locale)}):xIntercepts.length===1?strings.srQuadraticOneXIntercept({intercept:srFormatNumber(xIntercepts[0],locale)}):undefined;const srQuadraticYIntercept=strings.srQuadraticYIntercept({intercept:srFormatNumber(c,locale)});const srQuadraticInteractiveElements=strings.srInteractiveElements({elements:strings.srQuadraticInteractiveElements({point1X:srFormatNumber(state.coords[0][0],locale),point1Y:srFormatNumber(state.coords[0][1],locale),point2X:srFormatNumber(state.coords[1][0],locale),point2Y:srFormatNumber(state.coords[1][1],locale),point3X:srFormatNumber(state.coords[2][0],locale),point3Y:srFormatNumber(state.coords[2][1],locale)})});return {srQuadraticGraph,srQuadraticDirection,srQuadraticVertex,srQuadraticXIntercepts,srQuadraticYIntercept,srQuadraticInteractiveElements}}const getQuadraticKeyboardConstraint=(coords,snapStep,pointMoved)=>{const newCoords=[coords[0],coords[1],coords[2]];const coordToBeMoved=newCoords[pointMoved];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);newCoords[pointMoved]=movedCoord;if(areCoordsValid(newCoords)){return movedCoord}movedCoord=moveFunc(movedCoord);newCoords[pointMoved]=movedCoord;if(areCoordsValid(newCoords)){return movedCoord}return moveFunc(movedCoord)};return {up:mafs.vec.add(coordToBeMoved,[0,snapStep[1]]),down:mafs.vec.sub(coordToBeMoved,[0,snapStep[1]]),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const areCoordsValid=coords=>{const p1=coords[0];const p2=coords[1];const p3=coords[2];if(p1[0]===p2[0]||p2[0]===p3[0]||p1[0]===p3[0]){return false}return true};
2038
2038
 
2039
- function renderRayGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(RayGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getRayGraphDescription(state,i18n)}}const RayGraph=props=>{const{dispatch}=props;const{coords:line,pointLabels}=props.graphState;const handleMoveLine=newStart=>dispatch(actions.ray.moveRay(newStart));const handleMovePoint=(pointIndex,newPoint)=>dispatch(actions.ray.movePoint(pointIndex,newPoint));const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const{srRayGraph,srRayPoints,srRayEndpoint,srRayTerminalPoint,srRayGrabHandle}=describeRayGraph(props.graphState,{strings,locale});const point1AriaLabel=buildLabel(0,line[0])??srRayEndpoint;const point2AriaLabel=buildLabel(1,line[1])??srRayTerminalPoint;return jsxRuntimeExports.jsxs("g",{"aria-label":srRayGraph,"aria-describedby":pointsDescriptionId,children:[jsxRuntimeExports.jsx(MovableLine,{points:line,ariaLabels:{point1AriaLabel,point2AriaLabel,grabHandleAriaLabel:srRayGrabHandle},ariaLive:"off",onMoveLine:handleMoveLine,onMovePoint:handleMovePoint,extend:{start:false,end:true}}),jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srRayPoints})]})};function getRayGraphDescription(state,i18n){const strings=describeRayGraph(state,i18n);return strings.srRayInteractiveElement}function describeRayGraph(state,i18n){const{coords:line}=state;const{strings,locale}=i18n;const srRayGraph=strings.srRayGraph;const srRayPoints=strings.srRayPoints({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srRayEndpoint=strings.srRayEndpoint({x:srFormatNumber(line[0][0],locale),y:srFormatNumber(line[0][1],locale)});const srRayTerminalPoint=strings.srRayTerminalPoint({x:srFormatNumber(line[1][0],locale),y:srFormatNumber(line[1][1],locale)});const srRayGrabHandle=strings.srRayGrabHandle({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srRayInteractiveElement=strings.srInteractiveElements({elements:[srRayGraph,srRayPoints].join(" ")});return {srRayGraph,srRayPoints,srRayEndpoint,srRayTerminalPoint,srRayGrabHandle,srRayInteractiveElement}}
2039
+ function renderRayGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(RayGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getRayGraphDescription(state,i18n)}}const RayGraph=props=>{const{dispatch}=props;const{coords:line,pointLabels}=props.graphState;const handleMoveLine=newStart=>dispatch(actions.ray.moveRay(newStart));const handleMovePoint=(pointIndex,newPoint)=>dispatch(actions.ray.movePoint(pointIndex,newPoint));const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const{srRayGraph,srRayPoints,srRayEndpoint,srRayTerminalPoint,srRayGrabHandle}=describeRayGraph(props.graphState,{strings,locale});const point1AriaLabel=buildLabel(0,line[0])??srRayEndpoint;const point2AriaLabel=buildLabel(1,line[1])??srRayTerminalPoint;return jsxRuntimeExports.jsxs("g",{"aria-label":srRayGraph,"aria-describedby":pointsDescriptionId,children:[jsxRuntimeExports.jsx(MovableLine,{points:line,ariaLabels:{point1AriaLabel,point2AriaLabel,grabHandleAriaLabel:srRayGrabHandle},onMoveLine:handleMoveLine,onMovePoint:handleMovePoint,extend:{start:false,end:true}}),jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srRayPoints})]})};function getRayGraphDescription(state,i18n){const strings=describeRayGraph(state,i18n);return strings.srRayInteractiveElement}function describeRayGraph(state,i18n){const{coords:line}=state;const{strings,locale}=i18n;const srRayGraph=strings.srRayGraph;const srRayPoints=strings.srRayPoints({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srRayEndpoint=strings.srRayEndpoint({x:srFormatNumber(line[0][0],locale),y:srFormatNumber(line[0][1],locale)});const srRayTerminalPoint=strings.srRayTerminalPoint({x:srFormatNumber(line[1][0],locale),y:srFormatNumber(line[1][1],locale)});const srRayGrabHandle=strings.srRayGrabHandle({point1X:srFormatNumber(line[0][0],locale),point1Y:srFormatNumber(line[0][1],locale),point2X:srFormatNumber(line[1][0],locale),point2Y:srFormatNumber(line[1][1],locale)});const srRayInteractiveElement=strings.srInteractiveElements({elements:[srRayGraph,srRayPoints].join(" ")});return {srRayGraph,srRayPoints,srRayEndpoint,srRayTerminalPoint,srRayGrabHandle,srRayInteractiveElement}}
2040
2040
 
2041
- function renderSegmentGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(SegmentGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getSegmentGraphDescription(state,i18n)}}const SegmentGraph=({dispatch,graphState})=>{const{coords:segments,pointLabels}=graphState;const{strings,locale}=usePerseusI18n();const segmentUniqueId=React__namespace.useId();const lengthDescriptionId=segmentUniqueId+"-length";const wholeGraphDescriptionId=segmentUniqueId+"-whole-graph";const buildLabel=usePointAriaLabel(pointLabels);function getWholeSegmentGraphAriaLabel(){return segments?.length>1?strings.srMultipleSegmentGraphAriaLabel({countOfSegments:segments.length}):strings.srSingleSegmentGraphAriaLabel}const wholeSegmentGraphAriaLabel=getWholeSegmentGraphAriaLabel();function getIndividualSegmentAriaLabel(segment,index){if(segments.length===1){return strings.srSingleSegmentLabel({point1X:srFormatNumber(segments[0][0][X],locale),point1Y:srFormatNumber(segments[0][0][Y],locale),point2X:srFormatNumber(segments[0][1][X],locale),point2Y:srFormatNumber(segments[0][1][Y],locale)})}return strings.srMultipleSegmentIndividualLabel({point1X:srFormatNumber(segment[0][X],locale),point1Y:srFormatNumber(segment[0][Y],locale),point2X:srFormatNumber(segment[1][X],locale),point2Y:srFormatNumber(segment[1][Y],locale),indexOfSegment:index+1})}function getWholeSegmentGraphAriaDescription(){return segments.map((segment,index)=>getIndividualSegmentAriaLabel(segment,index)).join(" ")}function formatSegment(endpointNumber,x,y,index){const segObj={endpointNumber:endpointNumber,x:srFormatNumber(x,locale),y:srFormatNumber(y,locale)};return segments.length>1?strings.srMultipleSegmentGraphEndpointAriaLabel({...segObj,indexOfSegment:index}):strings.srSingleSegmentGraphEndpointAriaLabel(segObj)}return jsxRuntimeExports.jsxs("g",{"aria-label":wholeSegmentGraphAriaLabel,"aria-describedby":`${wholeGraphDescriptionId} ${segments.length===1&&lengthDescriptionId}`,children:[segments?.map((segment,i)=>{const point1AriaLabel=buildLabel(i*2,segment[0])??formatSegment(1,segment[0][X],segment[0][Y],i+1);const point2AriaLabel=buildLabel(i*2+1,segment[1])??formatSegment(2,segment[1][X],segment[1][Y],i+1);const grabHandleAriaLabel=strings.srSegmentGrabHandle({point1X:srFormatNumber(segment[0][X],locale),point1Y:srFormatNumber(segment[0][Y],locale),point2X:srFormatNumber(segment[1][X],locale),point2Y:srFormatNumber(segment[1][Y],locale)});return jsxRuntimeExports.jsxs("g",{"aria-label":segments.length===1?undefined:getIndividualSegmentAriaLabel(segment,i),"aria-describedby":segments.length===1?undefined:lengthDescriptionId,children:[jsxRuntimeExports.jsx(MovableLine,{points:segment,ariaLive:"off",onMoveLine:newStart=>{dispatch(actions.segment.moveLine(i,newStart));},onMovePoint:(endpointIndex,destination)=>{dispatch(actions.segment.movePointInFigure(i,endpointIndex,destination));},ariaLabels:{point1AriaLabel,point2AriaLabel,grabHandleAriaLabel}},i),jsxRuntimeExports.jsx(SRDescInSVG,{id:lengthDescriptionId,children:strings.srSegmentLength({length:srFormatNumber(getLengthOfSegment(segment),locale)})})]},`${segmentUniqueId}-${i}`)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:wholeGraphDescriptionId,children:getWholeSegmentGraphAriaDescription()})]})};function getLengthOfSegment(segment){return kmath.point.distanceToPoint(...segment)}function getSegmentGraphDescription(state,i18n){const{strings,locale}=i18n;const segmentDescriptions=state.coords.map(([point1,point2],index)=>strings.srMultipleSegmentIndividualLabel({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),indexOfSegment:index+1}));return strings.srInteractiveElements({elements:segmentDescriptions.join(" ")})}
2041
+ function renderSegmentGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(SegmentGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getSegmentGraphDescription(state,i18n)}}const SegmentGraph=({dispatch,graphState})=>{const{coords:segments,pointLabels}=graphState;const{strings,locale}=usePerseusI18n();const segmentUniqueId=React__namespace.useId();const lengthDescriptionId=segmentUniqueId+"-length";const wholeGraphDescriptionId=segmentUniqueId+"-whole-graph";const buildLabel=usePointAriaLabel(pointLabels);function getWholeSegmentGraphAriaLabel(){return segments?.length>1?strings.srMultipleSegmentGraphAriaLabel({countOfSegments:segments.length}):strings.srSingleSegmentGraphAriaLabel}const wholeSegmentGraphAriaLabel=getWholeSegmentGraphAriaLabel();function getIndividualSegmentAriaLabel(segment,index){if(segments.length===1){return strings.srSingleSegmentLabel({point1X:srFormatNumber(segments[0][0][X],locale),point1Y:srFormatNumber(segments[0][0][Y],locale),point2X:srFormatNumber(segments[0][1][X],locale),point2Y:srFormatNumber(segments[0][1][Y],locale)})}return strings.srMultipleSegmentIndividualLabel({point1X:srFormatNumber(segment[0][X],locale),point1Y:srFormatNumber(segment[0][Y],locale),point2X:srFormatNumber(segment[1][X],locale),point2Y:srFormatNumber(segment[1][Y],locale),indexOfSegment:index+1})}function getWholeSegmentGraphAriaDescription(){return segments.map((segment,index)=>getIndividualSegmentAriaLabel(segment,index)).join(" ")}function formatSegment(endpointNumber,x,y,index){const segObj={endpointNumber:endpointNumber,x:srFormatNumber(x,locale),y:srFormatNumber(y,locale)};return segments.length>1?strings.srMultipleSegmentGraphEndpointAriaLabel({...segObj,indexOfSegment:index}):strings.srSingleSegmentGraphEndpointAriaLabel(segObj)}return jsxRuntimeExports.jsxs("g",{"aria-label":wholeSegmentGraphAriaLabel,"aria-describedby":`${wholeGraphDescriptionId} ${segments.length===1&&lengthDescriptionId}`,children:[segments?.map((segment,i)=>{const point1AriaLabel=buildLabel(i*2,segment[0])??formatSegment(1,segment[0][X],segment[0][Y],i+1);const point2AriaLabel=buildLabel(i*2+1,segment[1])??formatSegment(2,segment[1][X],segment[1][Y],i+1);const grabHandleAriaLabel=strings.srSegmentGrabHandle({point1X:srFormatNumber(segment[0][X],locale),point1Y:srFormatNumber(segment[0][Y],locale),point2X:srFormatNumber(segment[1][X],locale),point2Y:srFormatNumber(segment[1][Y],locale)});return jsxRuntimeExports.jsxs("g",{"aria-label":segments.length===1?undefined:getIndividualSegmentAriaLabel(segment,i),"aria-describedby":segments.length===1?undefined:lengthDescriptionId,children:[jsxRuntimeExports.jsx(MovableLine,{points:segment,onMoveLine:newStart=>{dispatch(actions.segment.moveLine(i,newStart));},onMovePoint:(endpointIndex,destination)=>{dispatch(actions.segment.movePointInFigure(i,endpointIndex,destination));},ariaLabels:{point1AriaLabel,point2AriaLabel,grabHandleAriaLabel}},i),jsxRuntimeExports.jsx(SRDescInSVG,{id:lengthDescriptionId,children:strings.srSegmentLength({length:srFormatNumber(getLengthOfSegment(segment),locale)})})]},`${segmentUniqueId}-${i}`)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:wholeGraphDescriptionId,children:getWholeSegmentGraphAriaDescription()})]})};function getLengthOfSegment(segment){return kmath.point.distanceToPoint(...segment)}function getSegmentGraphDescription(state,i18n){const{strings,locale}=i18n;const segmentDescriptions=state.coords.map(([point1,point2],index)=>strings.srMultipleSegmentIndividualLabel({point1X:srFormatNumber(point1[X],locale),point1Y:srFormatNumber(point1[Y],locale),point2X:srFormatNumber(point2[X],locale),point2Y:srFormatNumber(point2[Y],locale),indexOfSegment:index+1}));return strings.srInteractiveElements({elements:segmentDescriptions.join(" ")})}
2042
2042
 
2043
- function renderSinusoidGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(SinusoidGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getSinusoidDescription(state,i18n)}}function SinusoidGraph(props){const{dispatch,graphState}=props;const{interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({amplitude:1,angularFrequency:1,phase:1,verticalOffset:0});const coeffs=getSinusoidCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const{srSinusoidGraph,srSinusoidDescription,srSinusoidRootPoint,srSinusoidPeakPoint}=describeSinusoidGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srSinusoidGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeSine(x,coeffRef.current),color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srSinusoidRootPoint:srSinusoidPeakPoint),point:coord,sequenceNumber:i+1,constrain:getSinusoidKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.sinusoid.movePoint(i,destination)),ariaLive:"off"},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srSinusoidDescription})]})}const getSinusoidKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[1]])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[1]])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const computeSine=function(x,sinusoidCoefficients){const{amplitude:a,angularFrequency:b,phase:c,verticalOffset:d}=sinusoidCoefficients;return a*Math.sin(b*x-c)+d};const getSinusoidCoefficients=coords=>{const p1=coords[0];const p2=coords[1];if(p2[X]===p1[X]){return}const amplitude=p2[Y]-p1[Y];const angularFrequency=Math.PI/(2*(p2[X]-p1[X]));const phase=p1[X]*angularFrequency;const verticalOffset=p1[Y];return {amplitude,angularFrequency,phase,verticalOffset}};function getSinusoidDescription(state,i18n){const strings=describeSinusoidGraph(state,i18n);return strings.srSinusoidInteractiveElements}function describeSinusoidGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[root,peak]=coords;const diffX=Math.abs(peak[X]-root[X]);const diffY=Math.abs(peak[Y]-root[Y]);const formattedRoot={x:srFormatNumber(root[X],locale),y:srFormatNumber(root[Y],locale)};const formattedPeak={x:srFormatNumber(peak[X],locale),y:srFormatNumber(peak[Y],locale)};const srSinusoidGraph=strings.srSinusoidGraph;const srSinusoidDescription=strings.srSinusoidDescription({minValue:srFormatNumber(root[Y]-diffY,locale),maxValue:srFormatNumber(root[Y]+diffY,locale),cycleStart:srFormatNumber(root[X]-2*diffX,locale),cycleEnd:srFormatNumber(root[X]+2*diffX,locale)});const srSinusoidRootPoint=strings.srSinusoidRootPoint(formattedRoot);const srSinusoidPeakPoint=peak[Y]===root[Y]?strings.srSinusoidFlatPoint(formattedPeak):peak[Y]>root[Y]?strings.srSinusoidMaxPoint(formattedPeak):strings.srSinusoidMinPoint(formattedPeak);const srSinusoidInteractiveElements=strings.srInteractiveElements({elements:strings.srSinusoidInteractiveElements({point1X:srFormatNumber(root[X],locale),point1Y:srFormatNumber(root[Y],locale),point2X:srFormatNumber(peak[X],locale),point2Y:srFormatNumber(peak[Y],locale)})});return {srSinusoidGraph,srSinusoidDescription,srSinusoidRootPoint,srSinusoidPeakPoint,srSinusoidInteractiveElements}}
2043
+ function renderSinusoidGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(SinusoidGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getSinusoidDescription(state,i18n)}}function SinusoidGraph(props){const{dispatch,graphState}=props;const{interactiveColor}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({amplitude:1,angularFrequency:1,phase:1,verticalOffset:0});const coeffs=getSinusoidCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const{srSinusoidGraph,srSinusoidDescription,srSinusoidRootPoint,srSinusoidPeakPoint}=describeSinusoidGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srSinusoidGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeSine(x,coeffRef.current),color:interactiveColor,svgPathProps:{"aria-hidden":true}})}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srSinusoidRootPoint:srSinusoidPeakPoint),point:coord,sequenceNumber:i+1,constrain:getSinusoidKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.sinusoid.movePoint(i,destination))},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srSinusoidDescription})]})}const getSinusoidKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[1]])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[1]])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const computeSine=function(x,sinusoidCoefficients){const{amplitude:a,angularFrequency:b,phase:c,verticalOffset:d}=sinusoidCoefficients;return a*Math.sin(b*x-c)+d};const getSinusoidCoefficients=coords=>{const p1=coords[0];const p2=coords[1];if(p2[X]===p1[X]){return}const amplitude=p2[Y]-p1[Y];const angularFrequency=Math.PI/(2*(p2[X]-p1[X]));const phase=p1[X]*angularFrequency;const verticalOffset=p1[Y];return {amplitude,angularFrequency,phase,verticalOffset}};function getSinusoidDescription(state,i18n){const strings=describeSinusoidGraph(state,i18n);return strings.srSinusoidInteractiveElements}function describeSinusoidGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[root,peak]=coords;const diffX=Math.abs(peak[X]-root[X]);const diffY=Math.abs(peak[Y]-root[Y]);const formattedRoot={x:srFormatNumber(root[X],locale),y:srFormatNumber(root[Y],locale)};const formattedPeak={x:srFormatNumber(peak[X],locale),y:srFormatNumber(peak[Y],locale)};const srSinusoidGraph=strings.srSinusoidGraph;const srSinusoidDescription=strings.srSinusoidDescription({minValue:srFormatNumber(root[Y]-diffY,locale),maxValue:srFormatNumber(root[Y]+diffY,locale),cycleStart:srFormatNumber(root[X]-2*diffX,locale),cycleEnd:srFormatNumber(root[X]+2*diffX,locale)});const srSinusoidRootPoint=strings.srSinusoidRootPoint(formattedRoot);const srSinusoidPeakPoint=peak[Y]===root[Y]?strings.srSinusoidFlatPoint(formattedPeak):peak[Y]>root[Y]?strings.srSinusoidMaxPoint(formattedPeak):strings.srSinusoidMinPoint(formattedPeak);const srSinusoidInteractiveElements=strings.srInteractiveElements({elements:strings.srSinusoidInteractiveElements({point1X:srFormatNumber(root[X],locale),point1Y:srFormatNumber(root[Y],locale),point2X:srFormatNumber(peak[X],locale),point2Y:srFormatNumber(peak[Y],locale)})});return {srSinusoidGraph,srSinusoidDescription,srSinusoidRootPoint,srSinusoidPeakPoint,srSinusoidInteractiveElements}}
2044
2044
 
2045
- function renderTangentGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(TangentGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getTangentDescription(state,i18n)}}function TangentGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({amplitude:1,angularFrequency:1,phase:1,verticalOffset:0});const coeffs=getTangentCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const xRange=[range[0][0],range[0][1]];const segments=getPlotSegments(coeffRef.current,xRange);const{srTangentGraph,srTangentDescription,srTangentInflectionPoint,srTangentSecondPoint}=describeTangentGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srTangentGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:segments.map(([segStart,segEnd],i)=>jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeTangent(x,coeffRef.current),domain:[segStart,segEnd],color:interactiveColor,svgPathProps:{"aria-hidden":true}},`tangent-segment-${i}`))}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srTangentInflectionPoint:srTangentSecondPoint),point:coord,sequenceNumber:i+1,constrain:getTangentKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.tangent.movePoint(i,destination)),ariaLive:"off"},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srTangentDescription})]})}const getTangentKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[1]])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[1]])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const computeTangent=function(x,tangentCoefficients){const{amplitude:a,angularFrequency:b,phase:c,verticalOffset:d}=tangentCoefficients;const arg=b*x-c;const normalized=(arg-Math.PI/2)/Math.PI%1;const distToAsymptote=Math.abs(normalized>.5?normalized-1:normalized<-0.5?normalized+1:normalized);if(distToAsymptote<.001){return NaN}return a*Math.tan(arg)+d};const getTangentCoefficients=coords=>{const p1=coords[0];const p2=coords[1];if(p2[X]===p1[X]){return}const amplitude=p2[Y]-p1[Y];const angularFrequency=Math.PI/(4*(p2[X]-p1[X]));const phase=p1[X]*angularFrequency;const verticalOffset=p1[Y];return {amplitude,angularFrequency,phase,verticalOffset}};function getAsymptotePositions(coeffs,xRange){const{angularFrequency:b,phase:c}=coeffs;if(b===0){return []}const period=Math.PI/Math.abs(b);const referenceAsymptote=(c+Math.PI/2)/b;const asymptotes=[];let x=referenceAsymptote;while(x>xRange[0]-period){if(x>xRange[0]&&x<xRange[1]){asymptotes.push(x);}x-=period;}x=referenceAsymptote+period;while(x<xRange[1]+period){if(x>xRange[0]&&x<xRange[1]){asymptotes.push(x);}x+=period;}return asymptotes.sort((a,b)=>a-b)}function getPlotSegments(coeffs,xRange){const asymptotes=getAsymptotePositions(coeffs,xRange);const eps=.01;const segments=[];let start=xRange[0];for(const asymptote of asymptotes){segments.push([start,asymptote-eps]);start=asymptote+eps;}segments.push([start,xRange[1]]);return segments}function getTangentDescription(state,i18n){return describeTangentGraph(state,i18n).srTangentInteractiveElements}function describeTangentGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[inflection,secondPoint]=coords;const formattedInflection={x:srFormatNumber(inflection[X],locale),y:srFormatNumber(inflection[Y],locale)};const formattedSecondPoint={x:srFormatNumber(secondPoint[X],locale),y:srFormatNumber(secondPoint[Y],locale)};const srTangentGraph=strings.srTangentGraph;const srTangentDescription=strings.srTangentDescription({inflectionX:srFormatNumber(inflection[X],locale),inflectionY:srFormatNumber(inflection[Y],locale)});const srTangentInflectionPoint=strings.srTangentInflectionPoint(formattedInflection);const srTangentSecondPoint=strings.srTangentSecondPoint(formattedSecondPoint);const srTangentInteractiveElements=strings.srInteractiveElements({elements:strings.srTangentInteractiveElements({point1X:srFormatNumber(inflection[X],locale),point1Y:srFormatNumber(inflection[Y],locale),point2X:srFormatNumber(secondPoint[X],locale),point2Y:srFormatNumber(secondPoint[Y],locale)})});return {srTangentGraph,srTangentDescription,srTangentInflectionPoint,srTangentSecondPoint,srTangentInteractiveElements}}
2045
+ function renderTangentGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(TangentGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getTangentDescription(state,i18n)}}function TangentGraph(props){const{dispatch,graphState}=props;const{interactiveColor,range}=useGraphConfig();const i18n=usePerseusI18n();const id=React__namespace.useId();const descriptionId=id+"-description";const{coords,pointLabels,snapStep}=graphState;const buildLabel=usePointAriaLabel(pointLabels);const coeffRef=React__namespace.useRef({amplitude:1,angularFrequency:1,phase:1,verticalOffset:0});const coeffs=getTangentCoefficients(coords);if(coeffs!==undefined){coeffRef.current=coeffs;}const xRange=[range[0][0],range[0][1]];const segments=getPlotSegments(coeffRef.current,xRange);const{srTangentGraph,srTangentDescription,srTangentInflectionPoint,srTangentSecondPoint}=describeTangentGraph(graphState,i18n);return jsxRuntimeExports.jsxs("g",{"aria-label":srTangentGraph,"aria-describedby":descriptionId,children:[jsxRuntimeExports.jsx(ClipToGraphBounds,{children:segments.map(([segStart,segEnd],i)=>jsxRuntimeExports.jsx(mafs.Plot.OfX,{y:x=>computeTangent(x,coeffRef.current),domain:[segStart,segEnd],color:interactiveColor,svgPathProps:{"aria-hidden":true}},`tangent-segment-${i}`))}),coords.map((coord,i)=>jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(i,coord)??(i===0?srTangentInflectionPoint:srTangentSecondPoint),point:coord,sequenceNumber:i+1,constrain:getTangentKeyboardConstraint(coords,snapStep,i),onMove:destination=>dispatch(actions.tangent.movePoint(i,destination))},"point-"+i)),jsxRuntimeExports.jsx(SRDescInSVG,{id:descriptionId,children:srTangentDescription})]})}const getTangentKeyboardConstraint=(coords,snapStep,pointIndex)=>{const coordToBeMoved=coords[pointIndex];const otherPoint=coords[1-pointIndex];const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(coordToBeMoved);if(movedCoord[X]===otherPoint[X]){movedCoord=moveFunc(movedCoord);}return movedCoord};return {up:movePointWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[1]])),down:movePointWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[1]])),left:movePointWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[0],0])),right:movePointWithConstraint(coord=>mafs.vec.add(coord,[snapStep[0],0]))}};const computeTangent=function(x,tangentCoefficients){const{amplitude:a,angularFrequency:b,phase:c,verticalOffset:d}=tangentCoefficients;const arg=b*x-c;const normalized=(arg-Math.PI/2)/Math.PI%1;const distToAsymptote=Math.abs(normalized>.5?normalized-1:normalized<-0.5?normalized+1:normalized);if(distToAsymptote<.001){return NaN}return a*Math.tan(arg)+d};const getTangentCoefficients=coords=>{const p1=coords[0];const p2=coords[1];if(p2[X]===p1[X]){return}const amplitude=p2[Y]-p1[Y];const angularFrequency=Math.PI/(4*(p2[X]-p1[X]));const phase=p1[X]*angularFrequency;const verticalOffset=p1[Y];return {amplitude,angularFrequency,phase,verticalOffset}};function getAsymptotePositions(coeffs,xRange){const{angularFrequency:b,phase:c}=coeffs;if(b===0){return []}const period=Math.PI/Math.abs(b);const referenceAsymptote=(c+Math.PI/2)/b;const asymptotes=[];let x=referenceAsymptote;while(x>xRange[0]-period){if(x>xRange[0]&&x<xRange[1]){asymptotes.push(x);}x-=period;}x=referenceAsymptote+period;while(x<xRange[1]+period){if(x>xRange[0]&&x<xRange[1]){asymptotes.push(x);}x+=period;}return asymptotes.sort((a,b)=>a-b)}function getPlotSegments(coeffs,xRange){const asymptotes=getAsymptotePositions(coeffs,xRange);const eps=.01;const segments=[];let start=xRange[0];for(const asymptote of asymptotes){segments.push([start,asymptote-eps]);start=asymptote+eps;}segments.push([start,xRange[1]]);return segments}function getTangentDescription(state,i18n){return describeTangentGraph(state,i18n).srTangentInteractiveElements}function describeTangentGraph(state,i18n){const{strings,locale}=i18n;const{coords}=state;const[inflection,secondPoint]=coords;const formattedInflection={x:srFormatNumber(inflection[X],locale),y:srFormatNumber(inflection[Y],locale)};const formattedSecondPoint={x:srFormatNumber(secondPoint[X],locale),y:srFormatNumber(secondPoint[Y],locale)};const srTangentGraph=strings.srTangentGraph;const srTangentDescription=strings.srTangentDescription({inflectionX:srFormatNumber(inflection[X],locale),inflectionY:srFormatNumber(inflection[Y],locale)});const srTangentInflectionPoint=strings.srTangentInflectionPoint(formattedInflection);const srTangentSecondPoint=strings.srTangentSecondPoint(formattedSecondPoint);const srTangentInteractiveElements=strings.srInteractiveElements({elements:strings.srTangentInteractiveElements({point1X:srFormatNumber(inflection[X],locale),point1Y:srFormatNumber(inflection[Y],locale),point2X:srFormatNumber(secondPoint[X],locale),point2Y:srFormatNumber(secondPoint[Y],locale)})});return {srTangentGraph,srTangentDescription,srTangentInflectionPoint,srTangentSecondPoint,srTangentInteractiveElements}}
2046
2046
 
2047
2047
  const hitboxSizePx=48;const ARROW_SCALE=1.5;const arrowPath=pathBuilder().move(-5,5).line(0,0).line(-5,-5).scale(ARROW_SCALE).build();function buildRoundedTriangle(tipX,tipY,armX,armY,backX,backY,backR,tipR){return pathBuilder().move(tipX,tipY).line(armX,armY).circularArc(backR,backX,backY,{sweep:true}).line(backX,-5).circularArc(backR,armX,-7.8,{sweep:true}).line(tipX,-2.8).circularArc(tipR,tipX,tipY,{sweep:true}).scale(ARROW_SCALE).build()}const arrowPathHalo=buildRoundedTriangle(2.8,2.8,-2.2,7.8,-9,5,4,4);const chevronPathAttrs={d:arrowPath,fill:"none",strokeLinejoin:"round",strokeLinecap:"round"};const MovableArrowheadView=React.forwardRef(function MovableArrowheadViewWithRef(props,hitboxRef){const{showTooltips,interactiveColor,disableKeyboardInteraction,snapStep}=useGraphConfig();const{point,angle,dragging,cursor,showFocusRing,onClick=()=>{}}=props;const wbColorName=disableKeyboardInteraction?"fadedOffBlack64":"blue";const classes=classNames("movable-arrowhead",dragging&&"movable-arrowhead--dragging",showFocusRing&&"movable-arrowhead--focus");const[[x,y]]=useTransformVectorsToPixels(point);const xSigFigs=countSignificantDecimals(snapStep[X]);const ySigFigs=countSignificantDecimals(snapStep[Y]);const xTickLabel=point[X].toFixed(xSigFigs);const yTickLabel=point[Y].toFixed(ySigFigs);const tooltipContent=`(${xTickLabel}, ${yTickLabel})`;const svgForArrowhead=jsxRuntimeExports.jsxs("g",{"aria-hidden":true,ref:hitboxRef,className:classes,style:{"--movable-arrowhead-color":interactiveColor,cursor},"data-testid":"movable-arrowhead",onClick:onClick,children:[jsxRuntimeExports.jsx("circle",{className:"movable-arrowhead-hitbox",r:hitboxSizePx/2,cx:x,cy:y}),jsxRuntimeExports.jsxs("g",{transform:`translate(${x} ${y}) rotate(${angle})`,children:[jsxRuntimeExports.jsx("path",{d:arrowPathHalo,className:"movable-arrowhead-halo"}),jsxRuntimeExports.jsx("path",{...chevronPathAttrs,className:"movable-arrowhead-ring"}),jsxRuntimeExports.jsx("path",{...chevronPathAttrs,className:"movable-arrowhead-center"})]})]});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:showTooltips?jsxRuntimeExports.jsx(Tooltip__default.default,{autoUpdate:true,opened:true,backgroundColor:wbColorName,content:tooltipContent,contentStyle:{color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default},children:svgForArrowhead}):svgForArrowhead})});function classNames(...names){return names.filter(Boolean).join(" ")}
2048
2048
 
2049
- function useControlArrowhead(params){const{snapStep,disableKeyboardInteraction}=useGraphConfig();const{point,angle,ariaDescribedBy,ariaLabel,ariaLive="polite",constrain=p=>snap(snapStep,p),sequenceNumber=1,onMove=noop,onDragEnd=noop}=params;const{strings,locale}=usePerseusI18n();const[focused,setFocused]=React.useState(false);const focusableHandleRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const visibleRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:visibleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const pointAriaLabel=ariaLabel||strings.srPointAtCoordinates({num:sequenceNumber,x:srFormatNumber(point[X],locale),y:srFormatNumber(point[Y],locale)});React.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const focusableHandle=jsxRuntimeExports.jsx("g",{"data-testid":"movable-arrowhead__focusable-handle",className:"movable-point__focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,ref:focusableHandleRef,role:"button","aria-describedby":ariaDescribedBy,"aria-label":pointAriaLabel,"aria-live":ariaLive,"aria-disabled":disableKeyboardInteraction,onFocus:()=>setFocused(true),onBlur:()=>setFocused(false)});const visibleArrowhead=jsxRuntimeExports.jsx(MovableArrowheadView,{point:point,angle:angle,dragging:dragging,focused:focused,ref:visibleRef,showFocusRing:focused,onClick:()=>{focusableHandleRef.current?.focus();}});return {focusableHandle,visibleArrowhead,dragging,focused}}const noop=()=>{};
2049
+ function useControlArrowhead(params){const{snapStep,disableKeyboardInteraction}=useGraphConfig();const{point,angle,ariaDescribedBy,ariaLabel,constrain=p=>snap(snapStep,p),sequenceNumber=1,onMove=noop,onDragEnd=noop}=params;const{strings,locale}=usePerseusI18n();const[focused,setFocused]=React.useState(false);const focusableHandleRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const visibleRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:visibleRef,point,onMove,onDragEnd,constrainKeyboardMovement:constrain});const pointAriaLabel=ariaLabel||strings.srPointAtCoordinates({num:sequenceNumber,x:srFormatNumber(point[X],locale),y:srFormatNumber(point[Y],locale)});React.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const focusableHandle=jsxRuntimeExports.jsx("g",{"data-testid":"movable-arrowhead__focusable-handle",className:"movable-point__focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,ref:focusableHandleRef,role:"button","aria-describedby":ariaDescribedBy,"aria-label":pointAriaLabel,"aria-disabled":disableKeyboardInteraction,onFocus:()=>setFocused(true),onBlur:()=>setFocused(false)});const visibleArrowhead=jsxRuntimeExports.jsx(MovableArrowheadView,{point:point,angle:angle,dragging:dragging,focused:focused,ref:visibleRef,showFocusRing:focused,onClick:()=>{focusableHandleRef.current?.focus();}});return {focusableHandle,visibleArrowhead,dragging,focused}}const noop=()=>{};
2050
2050
 
2051
- const{calculateAngleInDegrees: calculateAngleInDegrees$1}=kmath.angles;const LINE_PULLBACK_PX=4;function renderVectorGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(VectorGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getVectorGraphDescription(state,i18n)}}const VectorGraph=props=>{const{dispatch}=props;const{coords}=props.graphState;const[tail,tip]=coords;const{strings,locale}=usePerseusI18n();const{markings}=useGraphConfig();const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const{srVectorGraph,srVectorPoints,srVectorTipPoint,srVectorGrabHandle}=describeVectorGraph(props.graphState,{strings,locale});const tipArrowhead=useTipArrowhead({tail,tip,ariaLabel:srVectorTipPoint,ariaDescribedBy:pointsDescriptionId,onMove:destination=>dispatch(actions.vector.moveTip(destination))});const showHairlines=(tipArrowhead.dragging||tipArrowhead.focused)&&markings!=="none";return jsxRuntimeExports.jsxs("g",{"aria-label":srVectorGraph,"aria-describedby":pointsDescriptionId,children:[showHairlines&&jsxRuntimeExports.jsx(Hairlines,{point:tip}),jsxRuntimeExports.jsx(VectorBody,{tail:tail,tip:tip,ariaLabel:srVectorGrabHandle,ariaDescribedBy:pointsDescriptionId,onMove:newStart=>dispatch(actions.vector.moveVector(newStart))}),tipArrowhead.focusableHandle,tipArrowhead.visibleArrowhead,jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srVectorPoints})]})};const VectorBody=props=>{const{tail,tip,ariaLabel,ariaDescribedBy,onMove}=props;const{snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const[hovered,setHovered]=React.useState(false);const[focused,setFocused]=React.useState(false);const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const bodyRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:bodyRef,point:tail,onMove,onDragEnd:()=>{bodyRef.current?.blur();},constrainKeyboardMovement:p=>snap(snapStep,p)});const direction=mafs.vec.sub(tipPx,tailPx);const dirMag=mafs.vec.mag(direction);const angleDeg=calculateAngleInDegrees$1(direction);const lineEndPx=dirMag>0?[tipPx[X]-direction[X]/dirMag*LINE_PULLBACK_PX,tipPx[Y]-direction[Y]/dirMag*LINE_PULLBACK_PX]:tipPx;const handleT=1/2;const handlePx=[tailPx[X]+(tipPx[X]-tailPx[X])*handleT,tailPx[Y]+(tipPx[Y]-tailPx[Y])*handleT];const active=hovered||dragging||focused;return jsxRuntimeExports.jsxs("g",{ref:bodyRef,tabIndex:disableKeyboardInteraction?-1:0,"aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-disabled":disableKeyboardInteraction,"aria-live":"polite",className:"movable-line","data-testid":"movable-vector",style:{cursor:dragging?"grabbing":"grab"},role:"button",onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),onFocus:()=>setFocused(true),onBlur:()=>setFocused(false),children:[jsxRuntimeExports.jsx(SVGLine,{start:tailPx,end:lineEndPx,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:tailPx,end:lineEndPx,className:`movable-vector-line ${active?"movable-dragging":""}`,style:{stroke:interactiveColor,strokeWidth:wonderBlocksTokens.sizing.size_020},testId:"movable-vector__line"}),active&&jsxRuntimeExports.jsx(MovablePillHandle,{center:handlePx,rotation:angleDeg,active:active,focused:focused})]})};function useTipArrowhead(params){const{tail,tip,ariaLabel,ariaDescribedBy,onMove}=params;const{snapStep}=useGraphConfig();const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const direction=mafs.vec.sub(tipPx,tailPx);const angleDeg=calculateAngleInDegrees$1(direction);return useControlArrowhead({ariaLabel,ariaDescribedBy,point:tip,angle:angleDeg,sequenceNumber:1,onMove,constrain:getVectorTipKeyboardConstraint(tail,tip,snapStep)})}const getVectorTipKeyboardConstraint=(tail,tip,snapStep)=>{const moveWithConstraint=moveFunc=>{let moved=moveFunc(tip);if(mafs.vec.dist(moved,tail)===0){moved=moveFunc(moved);}return moved};return {up:moveWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[Y]])),down:moveWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[Y]])),left:moveWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[X],0])),right:moveWithConstraint(coord=>mafs.vec.add(coord,[snapStep[X],0]))}};function getVectorGraphDescription(state,i18n){const strings=describeVectorGraph(state,i18n);return strings.srVectorInteractiveElement}function describeVectorGraph(state,i18n){const{coords}=state;const[tail,tip]=coords;const{strings,locale}=i18n;const srVectorGraph=strings.srVectorGraph;const srVectorPoints=strings.srVectorPoints({tailX:srFormatNumber(tail[X],locale),tailY:srFormatNumber(tail[Y],locale),tipX:srFormatNumber(tip[X],locale),tipY:srFormatNumber(tip[Y],locale)});const srVectorTipPoint=strings.srVectorTipPoint({x:srFormatNumber(tip[X],locale),y:srFormatNumber(tip[Y],locale)});const srVectorGrabHandle=strings.srVectorGrabHandle({tailX:srFormatNumber(tail[X],locale),tailY:srFormatNumber(tail[Y],locale),tipX:srFormatNumber(tip[X],locale),tipY:srFormatNumber(tip[Y],locale)});const srVectorInteractiveElement=strings.srInteractiveElements({elements:[srVectorGraph,srVectorPoints].join(" ")});return {srVectorGraph,srVectorPoints,srVectorTipPoint,srVectorGrabHandle,srVectorInteractiveElement}}
2051
+ const{calculateAngleInDegrees: calculateAngleInDegrees$1}=kmath.angles;const LINE_PULLBACK_PX=4;function renderVectorGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(VectorGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getVectorGraphDescription(state,i18n)}}const VectorGraph=props=>{const{dispatch}=props;const{coords}=props.graphState;const[tail,tip]=coords;const{strings,locale}=usePerseusI18n();const{markings}=useGraphConfig();const id=React__namespace.useId();const pointsDescriptionId=id+"-points";const{srVectorGraph,srVectorPoints,srVectorTipPoint,srVectorGrabHandle}=describeVectorGraph(props.graphState,{strings,locale});const tipArrowhead=useTipArrowhead({tail,tip,ariaLabel:srVectorTipPoint,ariaDescribedBy:pointsDescriptionId,onMove:destination=>dispatch(actions.vector.moveTip(destination))});const showHairlines=(tipArrowhead.dragging||tipArrowhead.focused)&&markings!=="none";return jsxRuntimeExports.jsxs("g",{"aria-label":srVectorGraph,"aria-describedby":pointsDescriptionId,children:[showHairlines&&jsxRuntimeExports.jsx(Hairlines,{point:tip}),jsxRuntimeExports.jsx(VectorBody,{tail:tail,tip:tip,ariaLabel:srVectorGrabHandle,ariaDescribedBy:pointsDescriptionId,onMove:newStart=>dispatch(actions.vector.moveVector(newStart))}),tipArrowhead.focusableHandle,tipArrowhead.visibleArrowhead,jsxRuntimeExports.jsx(SRDescInSVG,{id:pointsDescriptionId,children:srVectorPoints})]})};const VectorBody=props=>{const{tail,tip,ariaLabel,ariaDescribedBy,onMove}=props;const{snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const[hovered,setHovered]=React.useState(false);const[focused,setFocused]=React.useState(false);const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const bodyRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:bodyRef,point:tail,onMove,onDragEnd:()=>{bodyRef.current?.blur();},constrainKeyboardMovement:p=>snap(snapStep,p)});const direction=mafs.vec.sub(tipPx,tailPx);const dirMag=mafs.vec.mag(direction);const angleDeg=calculateAngleInDegrees$1(direction);const lineEndPx=dirMag>0?[tipPx[X]-direction[X]/dirMag*LINE_PULLBACK_PX,tipPx[Y]-direction[Y]/dirMag*LINE_PULLBACK_PX]:tipPx;const handleT=1/2;const handlePx=[tailPx[X]+(tipPx[X]-tailPx[X])*handleT,tailPx[Y]+(tipPx[Y]-tailPx[Y])*handleT];const active=hovered||dragging||focused;return jsxRuntimeExports.jsxs("g",{ref:bodyRef,tabIndex:disableKeyboardInteraction?-1:0,"aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-disabled":disableKeyboardInteraction,className:"movable-line","data-testid":"movable-vector",style:{cursor:dragging?"grabbing":"grab"},role:"button",onMouseEnter:()=>setHovered(true),onMouseLeave:()=>setHovered(false),onFocus:()=>setFocused(true),onBlur:()=>setFocused(false),children:[jsxRuntimeExports.jsx(SVGLine,{start:tailPx,end:lineEndPx,style:{stroke:"transparent",strokeWidth:TARGET_SIZE}}),jsxRuntimeExports.jsx(SVGLine,{start:tailPx,end:lineEndPx,className:`movable-vector-line ${active?"movable-dragging":""}`,style:{stroke:interactiveColor,strokeWidth:wonderBlocksTokens.sizing.size_020},testId:"movable-vector__line"}),active&&jsxRuntimeExports.jsx(MovablePillHandle,{center:handlePx,rotation:angleDeg,active:active,focused:focused})]})};function useTipArrowhead(params){const{tail,tip,ariaLabel,ariaDescribedBy,onMove}=params;const{snapStep}=useGraphConfig();const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const direction=mafs.vec.sub(tipPx,tailPx);const angleDeg=calculateAngleInDegrees$1(direction);return useControlArrowhead({ariaLabel,ariaDescribedBy,point:tip,angle:angleDeg,sequenceNumber:1,onMove,constrain:getVectorTipKeyboardConstraint(tail,tip,snapStep)})}const getVectorTipKeyboardConstraint=(tail,tip,snapStep)=>{const moveWithConstraint=moveFunc=>{let moved=moveFunc(tip);if(mafs.vec.dist(moved,tail)===0){moved=moveFunc(moved);}return moved};return {up:moveWithConstraint(coord=>mafs.vec.add(coord,[0,snapStep[Y]])),down:moveWithConstraint(coord=>mafs.vec.sub(coord,[0,snapStep[Y]])),left:moveWithConstraint(coord=>mafs.vec.sub(coord,[snapStep[X],0])),right:moveWithConstraint(coord=>mafs.vec.add(coord,[snapStep[X],0]))}};function getVectorGraphDescription(state,i18n){const strings=describeVectorGraph(state,i18n);return strings.srVectorInteractiveElement}function describeVectorGraph(state,i18n){const{coords}=state;const[tail,tip]=coords;const{strings,locale}=i18n;const srVectorGraph=strings.srVectorGraph;const srVectorPoints=strings.srVectorPoints({tailX:srFormatNumber(tail[X],locale),tailY:srFormatNumber(tail[Y],locale),tipX:srFormatNumber(tip[X],locale),tipY:srFormatNumber(tip[Y],locale)});const srVectorTipPoint=strings.srVectorTipPoint({x:srFormatNumber(tip[X],locale),y:srFormatNumber(tip[Y],locale)});const srVectorGrabHandle=strings.srVectorGrabHandle({tailX:srFormatNumber(tail[X],locale),tailY:srFormatNumber(tail[Y],locale),tipX:srFormatNumber(tip[X],locale),tipY:srFormatNumber(tip[Y],locale)});const srVectorInteractiveElement=strings.srInteractiveElements({elements:[srVectorGraph,srVectorPoints].join(" ")});return {srVectorGraph,srVectorPoints,srVectorTipPoint,srVectorGrabHandle,srVectorInteractiveElement}}
2052
2052
 
2053
2053
  const{calculateAngleInDegrees,convertDegreesToRadians}=kmath.angles;const protractorImage="https://cdn.kastatic.org/images/perseus/protractor.svg";const centerToTopLeft=[-195,-190];const centerToRotationHandle=[-201,-15];function Protractor(){const staticUrl=getDependencies().staticUrl;const{range,snapStep}=useGraphConfig();const[[xMin,xMax],[yMin,yMax]]=range;const initialCenter=[lerp(xMin,xMax,.5),lerp(yMin,yMax,.25)];const[center,setCenter]=React.useState(initialCenter);const[rotationHandleOffset,setRotationHandleOffset]=React.useState(centerToRotationHandle);const draggableRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:draggableRef,onMove:point=>setCenter(bound$1({snapStep,range,point})),point:center,constrainKeyboardMovement:point=>bound$1({snapStep,range,point})});const rotationHandleRef=React.useRef(null);useDraggablePx({gestureTarget:rotationHandleRef,onMove:setRotationHandleOffset,point:rotationHandleOffset,constrain:constrainToCircle});const[centerPx]=useTransformVectorsToPixels(center);const topLeftPx=mafs.vec.add(centerPx,centerToTopLeft);const angle=calculateAngleInDegrees(rotationHandleOffset)-calculateAngleInDegrees(centerToRotationHandle);return jsxRuntimeExports.jsxs("g",{ref:draggableRef,transform:`translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,style:{transformOrigin:`${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,cursor:dragging?"grabbing":"grab"},children:[jsxRuntimeExports.jsx("image",{href:staticUrl(protractorImage)}),jsxRuntimeExports.jsx("g",{transform:`translate(5, ${-centerToTopLeft[1]})`,ref:rotationHandleRef,children:jsxRuntimeExports.jsx(RotationArrow,{})})]})}function RotationArrow(){const radius=175;const angleDeg=10;const angleRad=convertDegreesToRadians(angleDeg);const endX=radius*(1-Math.cos(angleRad));const endY=radius*-Math.sin(angleRad);const rotationArrow=pathBuilder().move(0,0).circularArc(radius,endX,endY,{sweep:true}).build();const arrowhead=pathBuilder().move(-8,0).line(0,10).line(8,0).build();const targetRadius=TARGET_SIZE/2;return jsxRuntimeExports.jsxs("g",{className:"protractor-rotation-handle",children:[jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrow-arc",d:rotationArrow}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead,transform:`translate(${endX}, ${endY}), rotate(${180+angleDeg})`}),jsxRuntimeExports.jsx("ellipse",{cx:"0px",cy:"-15px",rx:targetRadius,ry:targetRadius,fill:"none"})]})}const protractorRadius=mafs.vec.mag(centerToRotationHandle);function constrainToCircle(edgePoint){return mafs.vec.withMag(edgePoint,protractorRadius)}function useDraggablePx(args){const{gestureTarget:target,onMove,point,constrain=p=>p}=args;const pickupPx=React__namespace.useRef([0,0]);react.useDrag(state=>{const{event,first,movement:pixelMovement}=state;event?.stopPropagation();if(first){pickupPx.current=point;}if(mafs.vec.mag(pixelMovement)===0){return}onMove?.(constrain(mafs.vec.add(pickupPx.current,pixelMovement)));},{target,eventOptions:{passive:false}});}
2054
2054
 
2055
- const GRAPH_LEFT_MARGIN=20;const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription,widgetId}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React__namespace.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React__namespace.useRef(null);const{analytics}=useDependencies();const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"interactive-graph",widgetId:widgetId}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;const graphInfo={range:state.range,width,height};const[xAxisLabelLocation,yAxisLabelLocation]=getLabelPosition(graphInfo,labelLocation,tickStep);const needsExtraMargin=labelLocation==="alongEdge"&&yAxisLabelLocation[0]<-14*fontSizeYAxisLabelMultiplier;const marginLabelDiff=GRAPH_LEFT_MARGIN-fontSize*fontSizeYAxisLabelMultiplier;const marginWithExtraOffset=-1*(yAxisLabelLocation[X]-marginLabelDiff);const showsAxisLabels=props.markings==="graph"||props.markings==="axes";const hasXAxisLabel=!!(labels[0]&&labels[0].trim());const graphMarginBottom=getGraphBottomMargin(xAxisLabelLocation[Y],height,hasXAxisLabel,showsAxisLabels);return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,showAxisArrows:props.showAxisArrows,showAxisTicks:props.showAxisTicks,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph",role:"figure",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:needsExtraMargin?`${marginWithExtraOffset}px`:`${GRAPH_LEFT_MARGIN}px`,marginBottom:graphMarginBottom,pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId,state.type!=="none"&&!disableInteraction&&instructionsId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[fullGraphAriaDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n,xAxisLabelLocation:xAxisLabelLocation,yAxisLabelLocation:yAxisLabelLocation})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(mafs.Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures.length>0&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{position:"absolute"},children:jsxRuntimeExports.jsxs(mafs.Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[props.showProtractor&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(Protractor,{})}),graph]})})]}),interactionPrompt&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,border:`1px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "exponential":return renderExponentialGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};case "absolute-value":return renderAbsoluteValueGraph(state,dispatch,i18n);case "tangent":return renderTangentGraph(state,dispatch,i18n);case "logarithm":return renderLogarithmGraph(state,dispatch,i18n);case "vector":return renderVectorGraph(state,dispatch,i18n);default:throw new wonderStuffCore.UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
2055
+ const GRAPH_LEFT_MARGIN=20;const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription,widgetId}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React__namespace.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React__namespace.useRef(null);const{analytics}=useDependencies();const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"interactive-graph",widgetId:widgetId}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;const graphInfo={range:state.range,width,height};const[xAxisLabelLocation,yAxisLabelLocation]=getLabelPosition(graphInfo,labelLocation,tickStep);const needsExtraMargin=labelLocation==="alongEdge"&&yAxisLabelLocation[0]<-14*fontSizeYAxisLabelMultiplier;const marginLabelDiff=GRAPH_LEFT_MARGIN-fontSize*fontSizeYAxisLabelMultiplier;const marginWithExtraOffset=-1*(yAxisLabelLocation[X]-marginLabelDiff);const showsAxisLabels=props.markings==="graph"||props.markings==="axes";const hasXAxisLabel=!!(labels[0]&&labels[0].trim());const graphMarginBottom=getGraphBottomMargin(xAxisLabelLocation[Y],height,hasXAxisLabel,showsAxisLabels);return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,showAxisArrows:props.showAxisArrows,showAxisTicks:props.showAxisTicks,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph",role:"figure",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:needsExtraMargin?`${marginWithExtraOffset}px`:`${GRAPH_LEFT_MARGIN}px`,marginBottom:graphMarginBottom,pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(state.type!=="none"&&!disableInteraction&&instructionsId,fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[state.type!=="none"&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),fullGraphAriaDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n,xAxisLabelLocation:xAxisLabelLocation,yAxisLabelLocation:yAxisLabelLocation})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(mafs.Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures.length>0&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{position:"absolute"},children:jsxRuntimeExports.jsxs(mafs.Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[props.showProtractor&&jsxRuntimeExports.jsx(ClipToGraphBounds,{children:jsxRuntimeExports.jsx(Protractor,{})}),graph]})})]}),interactionPrompt&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,border:`1px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "exponential":return renderExponentialGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};case "absolute-value":return renderAbsoluteValueGraph(state,dispatch,i18n);case "tangent":return renderTangentGraph(state,dispatch,i18n);case "logarithm":return renderLogarithmGraph(state,dispatch,i18n);case "vector":return renderVectorGraph(state,dispatch,i18n);default:throw new wonderStuffCore.UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
2056
2056
 
2057
2057
  function mafsStateToInteractiveGraph(state,originalGraph){switch(state.type){case "angle":invariant__default.default(originalGraph.type==="angle");return {...originalGraph,coords:state.coords};case "quadratic":invariant__default.default(originalGraph.type==="quadratic");return {...originalGraph,coords:state.coords};case "circle":invariant__default.default(originalGraph.type==="circle");return {...originalGraph,center:state.center,radius:getRadius(state)};case "linear":invariant__default.default(originalGraph.type==="linear");return {...originalGraph,coords:state.coords};case "ray":invariant__default.default(originalGraph.type==="ray");return {...originalGraph,coords:state.coords};case "sinusoid":invariant__default.default(originalGraph.type==="sinusoid");return {...originalGraph,coords:state.coords};case "segment":invariant__default.default(originalGraph.type==="segment");return {...originalGraph,coords:state.coords};case "linear-system":invariant__default.default(originalGraph.type==="linear-system");return {...originalGraph,coords:state.coords};case "polygon":invariant__default.default(originalGraph.type==="polygon");return {...originalGraph,coords:state.coords};case "point":invariant__default.default(originalGraph.type==="point");return {...originalGraph,coords:state.coords};case "exponential":invariant__default.default(originalGraph.type==="exponential");return {...originalGraph,coords:state.coords,asymptote:state.asymptote};case "none":invariant__default.default(originalGraph.type==="none");return {...originalGraph};case "absolute-value":invariant__default.default(originalGraph.type==="absolute-value");return {...originalGraph,coords:state.coords};case "tangent":invariant__default.default(originalGraph.type==="tangent");return {...originalGraph,coords:state.coords};case "logarithm":invariant__default.default(originalGraph.type==="logarithm");return {...originalGraph,coords:state.coords,asymptote:state.asymptote};case "vector":invariant__default.default(originalGraph.type==="vector");return {...originalGraph,coords:state.coords};default:throw new wonderStuffCore.UnreachableCaseError(state)}}
2058
2058
 
2059
2059
  const StatefulMafsGraph=React__namespace.forwardRef(function StatefulMafsGraphWithRef(props,ref){const{onChange,graph}=props;const{strings,locale}=usePerseusI18n();const[state,dispatch]=React__namespace.useReducer(interactiveGraphReducer,props,initializeGraphState);React.useImperativeHandle(ref,()=>({getUserInput:()=>getGradableGraph(state,graph)}));const prevState=React.useRef(state);React.useEffect(()=>{if(prevState.current!==state){onChange(mafsStateToInteractiveGraph(state,graph));}prevState.current=state;},[onChange,state,graph]);React.useEffect(()=>{if(!state.stateAnnouncement){return}wonderBlocksAnnouncer.announceMessage({message:getAnnouncementText(state.stateAnnouncement,strings,locale)});},[state.stateAnnouncement,strings,locale]);const[xSnap,ySnap]=props.snapStep;React.useEffect(()=>{dispatch(changeSnapStep([xSnap,ySnap]));},[dispatch,xSnap,ySnap]);const[[xMinRange,xMaxRange],[yMinRange,yMaxRange]]=props.range;React.useEffect(()=>{dispatch(changeRange([[xMinRange,xMaxRange],[yMinRange,yMaxRange]]));},[dispatch,xMinRange,xMaxRange,yMinRange,yMaxRange]);const numSegments=graph.type==="segment"?graph.numSegments:null;const numPoints=graph.type==="point"?graph.numPoints:null;const numSides=graph.type==="polygon"?graph.numSides:null;const snapTo=graph.type==="polygon"?graph.snapTo:null;const showAngles=graph.type==="polygon"||graph.type==="angle"?graph.showAngles:null;const allowReflexAngles=graph.type==="angle"?graph.allowReflexAngles:null;const showSides=graph.type==="polygon"?graph.showSides:null;const startCoords="startCoords"in graph?graph.startCoords:undefined;const pointLabels="pointLabels"in graph?graph.pointLabels:undefined;const originalPropsRef=React.useRef(props);const latestPropsRef=wonderBlocksCore.useLatestRef(props);React.useEffect(()=>{if(latestPropsRef.current!==originalPropsRef.current){dispatch(reinitialize(latestPropsRef.current));}},[graph.type,numPoints,numSegments,numSides,snapTo,showAngles,showSides,latestPropsRef,startCoords,allowReflexAngles,pointLabels]);if(props.static&&props.correct&&props.graded!==false){return jsxRuntimeExports.jsx(MafsGraph,{...props,state:initializeGraphState({...props,graph:props.correct}),dispatch:dispatch})}return jsxRuntimeExports.jsx(MafsGraph,{...props,state:state,dispatch:dispatch})});
2060
2060
 
2061
- const defaultBackgroundImage={url:null};class InteractiveGraph extends React__namespace.Component{static getEquationString(props){return getEquationString(props)}getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};const showUngradedText=this.props.graded===false&&this.props.graph.type!=="none";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showUngradedText&&jsxRuntimeExports.jsx("p",{children:this.context.strings.ungradedInteractiveGraph}),jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly,widgetId:this.props.widgetId,graded:this.props.graded})]})}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.contextType=PerseusI18nContext;InteractiveGraph.defaultProps={labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true},showAxisTicks:{x:true,y:true},step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"linear"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$4(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$8,supportsUngraded:true};
2061
+ const defaultBackgroundImage={url:null};class InteractiveGraph extends React__namespace.Component{static getEquationString(props){return getEquationString(props)}getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};const showUngradedText=this.props.graded===false&&this.props.graph.type!=="none";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showUngradedText&&jsxRuntimeExports.jsx("p",{children:this.context.strings.ungradedInteractiveGraph}),jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly,widgetId:this.props.widgetId,graded:this.props.graded})]})}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.contextType=PerseusI18nContext;InteractiveGraph.defaultProps={labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true},showAxisTicks:{x:true,y:true},step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"none"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$4(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$8,supportsUngraded:true};
2062
2062
 
2063
2063
  const bodyXsmallBold={fontFamily:"inherit",fontSize:15,fontWeight:"bold",lineHeight:"22px"};
2064
2064
 
@@ -2066,19 +2066,19 @@ const getPromptJSON$a=widgetData=>{const propMarkers=widgetData.markers.map(mark
2066
2066
 
2067
2067
  const AnswerChoices=props=>{const{strings}=usePerseusI18n();const onAnswerChange=selected=>{const{choices,onChange}=props;onChange(choices.map(choice=>selected.includes(choice.content)));};const AnswerItems=choices=>choices.map(({content})=>jsxRuntimeExports.jsx(wonderBlocksDropdown.OptionItem,{value:content,label:jsxRuntimeExports.jsx(Renderer,{content:content,strings:strings,inline:true})},content));const selectedValues=props.choices.filter(choice=>choice.checked).map(choice=>choice.content);const{opener,onToggle,disabled}=props;const args={style:{zIndex:"unset"},children:AnswerItems(props.choices),opener,onToggle,disabled};return props.multipleSelect?jsxRuntimeExports.jsx(wonderBlocksDropdown.MultiSelect,{...args,selectedValues:selectedValues,onChange:selected=>onAnswerChange(selected)}):jsxRuntimeExports.jsx(wonderBlocksDropdown.SingleSelect,{...args,selectedValue:selectedValues[0],onChange:selected=>onAnswerChange([selected]),placeholder:props.choices[0].content})};
2068
2068
 
2069
- const HideAnswersToggle=props=>{const switchId=React.useId();const labelId=React.useId();const{strings}=usePerseusI18n();return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$c.switchWrapper,children:[jsxRuntimeExports.jsx(Switch__default.default,{id:switchId,checked:props.areAnswersHidden,onChange:props.onChange,"aria-labelledby":labelId}),jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{id:labelId,htmlFor:switchId,tag:"label",children:strings.hideAnswersToggleLabel})]})};const styles$c=aphrodite.StyleSheet.create({switchWrapper:{display:"flex",flexDirection:"row",flexWrap:"wrap-reverse",alignItems:"center",gap:"0.5em",marginTop:"1em"}});
2069
+ const HideAnswersToggle=props=>{const switchId=React.useId();const labelId=React.useId();const{strings}=usePerseusI18n();return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$d.switchWrapper,children:[jsxRuntimeExports.jsx(Switch__default.default,{id:switchId,checked:props.areAnswersHidden,onChange:props.onChange,"aria-labelledby":labelId}),jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{id:labelId,htmlFor:switchId,tag:"label",children:strings.hideAnswersToggleLabel})]})};const styles$d=aphrodite.StyleSheet.create({switchWrapper:{display:"flex",flexDirection:"row",flexWrap:"wrap-reverse",alignItems:"center",gap:"0.5em",marginTop:"1em"}});
2070
2070
 
2071
- const BringToFront={boxShadow:`0 8px 8px ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`,zIndex:1e3};const AnswerPill=props=>{const{selectedAnswers,showCorrectness,markerRef,side,onClick,style,focused,hovered}=props;const pillId=React.useId();const{strings}=usePerseusI18n();const answerString=selectedAnswers.length>1?strings.answers({num:selectedAnswers.length}):selectedAnswers[0];const correct=showCorrectness==="correct";const incorrect=showCorrectness==="incorrect";return jsxRuntimeExports.jsx(reactPopper.Popper,{placement:side,referenceElement:markerRef,modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({ref,style:popperStyle})=>jsxRuntimeExports.jsx(Pill__default.default,{size:"large",kind:"accent",id:pillId,onClick:correct?undefined:onClick,ref:ref,style:[style,popperStyle,styles$b.pill,correct&&styles$b.correct,incorrect&&styles$b.incorrect,(focused||hovered)&&BringToFront],children:jsxRuntimeExports.jsx(Renderer,{content:answerString,strings:strings,inline:true})})})};const styles$b=aphrodite.StyleSheet.create({correct:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.success.strong},incorrect:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.default},pill:{height:"auto"}});
2071
+ const BringToFront={boxShadow:`0 8px 8px ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`,zIndex:1e3};const AnswerPill=props=>{const{selectedAnswers,showCorrectness,markerRef,side,onClick,style,focused,hovered}=props;const pillId=React.useId();const{strings}=usePerseusI18n();const answerString=selectedAnswers.length>1?strings.answers({num:selectedAnswers.length}):selectedAnswers[0];const correct=showCorrectness==="correct";const incorrect=showCorrectness==="incorrect";return jsxRuntimeExports.jsx(reactPopper.Popper,{placement:side,referenceElement:markerRef,modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({ref,style:popperStyle})=>jsxRuntimeExports.jsx(Pill__default.default,{size:"large",kind:"accent",id:pillId,onClick:correct?undefined:onClick,ref:ref,style:[style,popperStyle,styles$c.pill,correct&&styles$c.correct,incorrect&&styles$c.incorrect,(focused||hovered)&&BringToFront],children:jsxRuntimeExports.jsx(Renderer,{content:answerString,strings:strings,inline:true})})})};const styles$c=aphrodite.StyleSheet.create({correct:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.success.strong},incorrect:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.neutral.default},pill:{height:"auto"}});
2072
2072
 
2073
- function shouldReduceMotion(){if(typeof window.matchMedia!=="function"){return true}const mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)");return !mediaQuery||mediaQuery.matches}const MARKER_SIZE=24;class Marker extends React__namespace.Component{componentDidMount(){this._mounted=true;}componentWillUnmount(){this._mounted=false;}renderIcon(){const{selected,showCorrectness,showSelected,showPulsate}=this.props;const isOpen=showSelected;const selectedAnswers=selected;let iconStyles;const iconNull={path:"",height:1,width:1};let args={size:MARKER_SIZE,color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default,icon:iconNull};if(showCorrectness){iconStyles=[styles$a.markerGraded,showCorrectness==="correct"?styles$a.markerCorrect:styles$a.markerIncorrect,isOpen&&styles$a.markerSelected];args={...args,icon:showCorrectness==="correct"?iconCheck:iconMinus};}else if(selectedAnswers&&selectedAnswers.length>0){iconStyles=[styles$a.markerFilled,isOpen&&styles$a.markerSelected];}else if(isOpen){iconStyles=[styles$a.markerSelected];args={...args,icon:iconChevronDown,size:8};}else if(showPulsate){iconStyles=[styles$a.markerPulsateBase,this._mounted&&shouldReduceMotion()?showPulsate&&styles$a.markerUnfilledPulsateOnce:showPulsate&&styles$a.markerUnfilledPulsateInfinite];}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$a.markerIcon,iconStyles],ref:node=>this._icon=node,children:jsxRuntimeExports.jsx(Icon,{...args})})}render(){const{showCorrectness,selected,showAnswer,answerSide,answerStyles,hovered,focused,label}=this.props;const markerDisabled=showCorrectness==="correct";const active=hovered||focused;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$a.marker,active&&!markerDisabled&&styles$a.markerActive],"aria-label":markerDisabled?this.context.strings.correctExcited:label,children:this.renderIcon()}),!!selected&&showAnswer&&jsxRuntimeExports.jsx(AnswerPill,{selectedAnswers:selected,showCorrectness:showCorrectness,side:answerSide,style:answerStyles,markerRef:this._icon??undefined,hovered:hovered,focused:focused})]})}constructor(...args){super(...args),this._mounted=false;}}Marker.contextType=PerseusI18nContext;Marker.defaultProps={selected:[]};const styles$a=aphrodite.StyleSheet.create({marker:{position:"absolute",backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:MARKER_SIZE,width:MARKER_SIZE,height:MARKER_SIZE,marginLeft:MARKER_SIZE/-2,marginTop:MARKER_SIZE/-2,boxShadow:wonderBlocksTokens.boxShadow.mid},markerIcon:{display:"flex",alignItems:"center",justifyContent:"center",boxSizing:"border-box",width:MARKER_SIZE,height:MARKER_SIZE,border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`,borderRadius:MARKER_SIZE},markerPulsateBase:{animationName:{"0%":{transform:"scale(1)",backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default},"100%":{transform:"scale(1.3)",backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default}},animationDirection:"alternate",animationDuration:"0.8s",animationTimingFunction:"ease-in",transformOrigin:"50% 50%",animationIterationCount:"0"},markerUnfilledPulsateInfinite:{animationIterationCount:"infinite"},markerUnfilledPulsateOnce:{animationIterationCount:"2"},markerActive:{outline:`2px solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`,outlineOffset:2},markerSelected:{boxShadow:wonderBlocksTokens.boxShadow.mid,border:`solid 4px ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`,backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default,borderRadius:MARKER_SIZE,transform:"rotate(180deg)"},markerFilled:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.subtle,border:`4px solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`},markerGraded:{width:MARKER_SIZE,height:MARKER_SIZE,justifyContent:"center",alignItems:"center",border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`},markerCorrect:{background:wonderBlocksTokens.semanticColor.core.background.success.strong},markerIncorrect:{background:wonderBlocksTokens.semanticColor.core.background.neutral.default}});
2073
+ function shouldReduceMotion(){if(typeof window.matchMedia!=="function"){return true}const mediaQuery=window.matchMedia("(prefers-reduced-motion: reduce)");return !mediaQuery||mediaQuery.matches}const MARKER_SIZE=24;class Marker extends React__namespace.Component{componentDidMount(){this._mounted=true;}componentWillUnmount(){this._mounted=false;}renderIcon(){const{selected,showCorrectness,showSelected,showPulsate}=this.props;const isOpen=showSelected;const selectedAnswers=selected;let iconStyles;const iconNull={path:"",height:1,width:1};let args={size:MARKER_SIZE,color:wonderBlocksTokens.semanticColor.core.foreground.knockout.default,icon:iconNull};if(showCorrectness){iconStyles=[styles$b.markerGraded,showCorrectness==="correct"?styles$b.markerCorrect:styles$b.markerIncorrect,isOpen&&styles$b.markerSelected];args={...args,icon:showCorrectness==="correct"?iconCheck:iconMinus};}else if(selectedAnswers&&selectedAnswers.length>0){iconStyles=[styles$b.markerFilled,isOpen&&styles$b.markerSelected];}else if(isOpen){iconStyles=[styles$b.markerSelected];args={...args,icon:iconChevronDown,size:8};}else if(showPulsate){iconStyles=[styles$b.markerPulsateBase,this._mounted&&shouldReduceMotion()?showPulsate&&styles$b.markerUnfilledPulsateOnce:showPulsate&&styles$b.markerUnfilledPulsateInfinite];}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$b.markerIcon,iconStyles],ref:node=>this._icon=node,children:jsxRuntimeExports.jsx(Icon,{...args})})}render(){const{showCorrectness,selected,showAnswer,answerSide,answerStyles,hovered,focused,label}=this.props;const markerDisabled=showCorrectness==="correct";const active=hovered||focused;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$b.marker,active&&!markerDisabled&&styles$b.markerActive],"aria-label":markerDisabled?this.context.strings.correctExcited:label,children:this.renderIcon()}),!!selected&&showAnswer&&jsxRuntimeExports.jsx(AnswerPill,{selectedAnswers:selected,showCorrectness:showCorrectness,side:answerSide,style:answerStyles,markerRef:this._icon??undefined,hovered:hovered,focused:focused})]})}constructor(...args){super(...args),this._mounted=false;}}Marker.contextType=PerseusI18nContext;Marker.defaultProps={selected:[]};const styles$b=aphrodite.StyleSheet.create({marker:{position:"absolute",backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:MARKER_SIZE,width:MARKER_SIZE,height:MARKER_SIZE,marginLeft:MARKER_SIZE/-2,marginTop:MARKER_SIZE/-2,boxShadow:wonderBlocksTokens.boxShadow.mid},markerIcon:{display:"flex",alignItems:"center",justifyContent:"center",boxSizing:"border-box",width:MARKER_SIZE,height:MARKER_SIZE,border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.neutral.default}`,borderRadius:MARKER_SIZE},markerPulsateBase:{animationName:{"0%":{transform:"scale(1)",backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default},"100%":{transform:"scale(1.3)",backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default}},animationDirection:"alternate",animationDuration:"0.8s",animationTimingFunction:"ease-in",transformOrigin:"50% 50%",animationIterationCount:"0"},markerUnfilledPulsateInfinite:{animationIterationCount:"infinite"},markerUnfilledPulsateOnce:{animationIterationCount:"2"},markerActive:{outline:`2px solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`,outlineOffset:2},markerSelected:{boxShadow:wonderBlocksTokens.boxShadow.mid,border:`solid 4px ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`,backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.default,borderRadius:MARKER_SIZE,transform:"rotate(180deg)"},markerFilled:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.instructive.subtle,border:`4px solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`},markerGraded:{width:MARKER_SIZE,height:MARKER_SIZE,justifyContent:"center",alignItems:"center",border:`2px solid ${wonderBlocksTokens.semanticColor.core.border.knockout.default}`},markerCorrect:{background:wonderBlocksTokens.semanticColor.core.background.success.strong},markerIncorrect:{background:wonderBlocksTokens.semanticColor.core.background.neutral.default}});
2074
2074
 
2075
- function isAnswerful(marker){return marker.answers!=null}function getComputedSelectedState(marker,userInputMarker,reviewMode,showSolutions){const shouldShowFeedback=showSolutions==="all"||reviewMode;if(!shouldShowFeedback){return userInputMarker}if(isAnswerful(marker)){return {...userInputMarker,selected:marker.answers}}else {return {...userInputMarker,selected:undefined}}}class LabelImage extends React__namespace.Component{static pointInTriangle(p,a,b,c){const sign=(p1,p2,p3)=>(p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y);const b1=sign(p,a,b)<0;const b2=sign(p,b,c)<0;const b3=sign(p,c,a)<0;return b1===b2&&b2===b3}static imageSideForMarkerPosition(x,y,preferredDirection){if(preferredDirection&&preferredDirection!=="NONE"){if(preferredDirection==="LEFT"&&x>20){return "right"}else if(preferredDirection==="RIGHT"&&x<80){return "left"}else if(preferredDirection==="UP"&&y>20){return "bottom"}else if(preferredDirection==="DOWN"&&y<80){return "top"}}if(x<20){return "left"}if(x>80){return "right"}const tl={x:20,y:0};const tr={x:80,y:0};const br={x:80,y:100};const bl={x:20,y:100};const cp={x:50,y:50};const sides=["top","right","bottom","left"];const triangles={top:[tl,tr,cp],right:[cp,tr,br],bottom:[bl,cp,br],left:[tl,cp,bl]};const p={x,y};for(const side of sides){const corners=triangles[side];if(LabelImage.pointInTriangle(p,...corners)){return side}}return "center"}static navigateToMarkerIndex(navigateDirection,markers,thisIndex){const thisMarker=markers[thisIndex];const sortedMarkers=markers.map((otherMarker,index)=>{const x=otherMarker.x-thisMarker.x;const y=otherMarker.y-thisMarker.y;const dist=Math.sqrt(x**2+y**2);return {index,dist,dir:{x:dist!==0?x/dist:0,y:dist!==0?y/dist:0}}}).filter(marker=>{if(marker.index===thisIndex){return false}return markers[marker.index].showCorrectness!=="correct"}).sort((a,b)=>{const distA=Math.round(a.dist*(navigateDirection.x*a.dir.x+navigateDirection.y*a.dir.y));const distB=Math.round(b.dist*(navigateDirection.x*b.dir.x+navigateDirection.y*b.dir.y));let dirA;let dirB;if(navigateDirection.x>0){dirA=a.dir.x>0&&distA!==0;dirB=b.dir.x>0&&distB!==0;}else if(navigateDirection.x<0){dirA=a.dir.x<0&&distA!==0;dirB=b.dir.x<0&&distB!==0;}else if(navigateDirection.y>0){dirA=a.dir.y>0&&distA!==0;dirB=b.dir.y>0&&distB!==0;}else if(navigateDirection.y<0){dirA=a.dir.y<0&&distA!==0;dirB=b.dir.y<0&&distB!==0;}if(dirA!==dirB){if(dirA){return -1}return 1}return distA-distB});return sortedMarkers.length>0?sortedMarkers[0].index:thisIndex}componentDidMount(){this.props.analytics?.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"label-image",widgetId:this.props.widgetId}});this._mounted=true;}componentWillUnmount(){this._mounted=false;}getPromptJSON(){return getPromptJSON$a(this.props)}handleMarkerChange(index,marker){const{userInput,handleUserInput}=this.props;const updatedUserInput=[...userInput.markers.slice(0,index),{label:marker.label,selected:marker.selected},...userInput.markers.slice(index+1)];handleUserInput({markers:updatedUserInput});}activateMarker(index,opened){this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:marker-interacted-with",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:marker-interacted-with:ti",payload:null});const{activeMarkerIndex}=this.state;if(activeMarkerIndex!==index&&opened){this.setState({activeMarkerIndex:index,markersInteracted:true});}else {this.setState({activeMarkerIndex:-1});}}handleMarkerKeyDown(index,e){const{markers}=this.props;if(markers.length<2){return}const directions={ArrowUp:{x:0,y:-1},ArrowRight:{x:1,y:0},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0}};if(!(e.key in directions)){return}const navigateDirection=directions[e.key];e.preventDefault();const marker=this._markers[LabelImage.navigateToMarkerIndex(navigateDirection,markers,index)];if(marker){ReactDOM__namespace.findDOMNode(marker).focus();}}handleAnswerChoicesChangeForMarker(index,selection){const{choices,markers}=this.props;const selected=choices.filter((_,index)=>selection[index]);this.handleMarkerChange(index,{...markers[index],selected:selected.length>0?selected:undefined});}renderMarkers(){const{markers,preferredPopoverDirection,userInput}=this.props;const{markersInteracted,activeMarkerIndex}=this.state;const isNarrowPage=this._mounted&&window.matchMedia(mediaQueries.xsOrSmaller.replace("@media ","")).matches;const isWideImage=this.props.imageWidth/2>this.props.imageHeight;return markers.map((marker,index)=>{const userInputMarker=userInput.markers[index];let side;let markerPosition;if(isNarrowPage||isWideImage){side=marker.y>50?"top":"bottom";markerPosition=marker.y>50?"bottom":"top";}else {markerPosition=LabelImage.imageSideForMarkerPosition(marker.x,marker.y,preferredPopoverDirection);if(markerPosition==="center"){markerPosition="bottom";}side=({left:"right",top:"bottom",right:"left",bottom:"top"})[markerPosition];}const computedSelectedState=getComputedSelectedState(marker,userInputMarker,this.props.reviewMode,this.props.showSolutions);let score;if(isAnswerful(marker)){score=perseusScore.scoreLabelImageMarker(computedSelectedState.selected,marker.answers);}else {score={hasAnswers:false,isCorrect:false};}const shouldShowFeedback=this.props.showSolutions==="all"||this.props.reviewMode;const showCorrectness=shouldShowFeedback&&score.isCorrect?"correct":marker.showCorrectness;const disabled=shouldShowFeedback;const isActiveAnswerChoice=activeMarkerIndex===index;const showAnswerChoice=computedSelectedState.selected&&!this.state.hideAnswers&&!isActiveAnswerChoice;const adjustPillDistance={[`margin${markerPosition.charAt(0).toUpperCase()+markerPosition.slice(1)}`]:10};return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{position:"absolute",left:`${marker.x}%`,top:`${marker.y}%`,zIndex:"unset"},children:jsxRuntimeExports.jsx(AnswerChoices,{choices:this.props.choices.map(choice=>({content:choice,checked:computedSelectedState.selected?computedSelectedState.selected.includes(choice):false})),multipleSelect:this.props.multipleAnswers,onChange:selection=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:choiced-interacted-with",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:choiced-interacted-with:ti",payload:null});this.handleAnswerChoicesChangeForMarker(index,selection);},onToggle:opened=>this.activateMarker(index,opened),disabled:disabled,opener:({opened})=>jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-expanded":opened,children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(Marker,{label:marker.label,showCorrectness:showCorrectness,showSelected:opened,showPulsate:!markersInteracted,ref:node=>this._markers[index]=node,showAnswer:showAnswerChoice,answerSide:side,answerStyles:adjustPillDistance,focused:focused||pressed,hovered:hovered,selected:computedSelectedState.selected})},`marker-${marker.x}.${marker.y}`)},`answers-${marker.x}.${marker.y}`)},index)})}renderInstructions(){const{apiOptions:{isMobile},choices,multipleAnswers,hideChoicesFromInstructions:hideChoices}=this.props;const{strings}=this.context;const promptString=isMobile?multipleAnswers?strings.tapMultiple:strings.tapSingle:multipleAnswers?strings.clickMultiple:strings.clickSingle;const choicesString=strings.choices;return jsxRuntimeExports.jsxs("div",{className:classNames__default.default("perseus-label-image-widget-instructions",aphrodite.css(styles$9.instructions)),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$9.instructionsCaption),children:[promptString," ",!hideChoices&&choicesString]}),!hideChoices&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$9.instructionsChoices),children:choices.map((choice,index)=>jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$9.instructionsChoice),children:jsxRuntimeExports.jsx(Renderer,{content:choice,strings:strings})},index))})]})}getSerializedState(){const{userInput,markers,...rest}=this.props;return {...rest,markers:markers.map((marker,index)=>({...marker,selected:userInput.markers[index].selected}))}}render(){const{imageAlt,imageUrl,imageWidth,imageHeight}=this.props;const{activeMarkerIndex}=this.state;return jsxRuntimeExports.jsxs("div",{children:[this.renderInstructions(),jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$9.markersCanvas),style:{maxWidth:imageWidth,maxHeight:imageHeight},children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$9.imageContainer,activeMarkerIndex!==-1&&styles$9.imageInteractionDisabled),children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{alt:imageAlt,src:imageUrl,width:imageWidth,height:imageHeight,setAssetStatus:setAssetStatus,allowZoom:true})})}),this.renderMarkers()]}),jsxRuntimeExports.jsx(HideAnswersToggle,{areAnswersHidden:this.state.hideAnswers,onChange:hideAnswers=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:toggle-answers-hidden",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:toggle-answers-hidden:ti",payload:null});this.setState({hideAnswers});}})]})}constructor(props){super(props),this._mounted=false;this._markers=[];this.state={activeMarkerIndex:-1,markersInteracted:false,hideAnswers:false};}}LabelImage.contextType=PerseusI18nContext;const LabelImageWithDependencies=React__namespace.forwardRef((props,ref)=>{const deps=useDependencies();return jsxRuntimeExports.jsx(LabelImage,{ref:ref,analytics:deps.analytics,...props})});function getStartUserInput$7(options){return {markers:options.markers.map(m=>({label:m.label}))}}function getUserInputFromSerializedState$7(serializedState){return {markers:serializedState.markers.map(m=>({label:m.label,selected:m.selected}))}}function getCorrectUserInput$3(options){return {markers:options.markers.map(marker=>({label:marker.label,selected:marker.answers}))}}var LabelImage$1 = {name:"label-image",displayName:"Label Image",widget:LabelImageWithDependencies,isLintable:true,getStartUserInput: getStartUserInput$7,getCorrectUserInput: getCorrectUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$7};const styles$9=aphrodite.StyleSheet.create({instructions:{paddingBottom:16},instructionsCaption:{...bodyXsmallBold,paddingBottom:16},instructionsChoices:{display:"flex",flexWrap:"wrap",margin:"-8px 0"},instructionsChoice:{display:"flex",alignItems:"center",margin:"8px 0",":not(:last-child)":{"::after":{content:"''",display:"inline-block",position:"relative",width:2,height:2,marginLeft:5,marginRight:5,background:wonderBlocksTokens.semanticColor.core.border.neutral.default,borderRadius:2}}},markersCanvas:{position:"relative"},imageContainer:{display:"flex"},imageInteractionDisabled:{pointerEvents:"none"}});
2075
+ function isAnswerful(marker){return marker.answers!=null}function getComputedSelectedState(marker,userInputMarker,reviewMode,showSolutions){const shouldShowFeedback=showSolutions==="all"||reviewMode;if(!shouldShowFeedback){return userInputMarker}if(isAnswerful(marker)){return {...userInputMarker,selected:marker.answers}}else {return {...userInputMarker,selected:undefined}}}class LabelImage extends React__namespace.Component{static pointInTriangle(p,a,b,c){const sign=(p1,p2,p3)=>(p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y);const b1=sign(p,a,b)<0;const b2=sign(p,b,c)<0;const b3=sign(p,c,a)<0;return b1===b2&&b2===b3}static imageSideForMarkerPosition(x,y,preferredDirection){if(preferredDirection&&preferredDirection!=="NONE"){if(preferredDirection==="LEFT"&&x>20){return "right"}else if(preferredDirection==="RIGHT"&&x<80){return "left"}else if(preferredDirection==="UP"&&y>20){return "bottom"}else if(preferredDirection==="DOWN"&&y<80){return "top"}}if(x<20){return "left"}if(x>80){return "right"}const tl={x:20,y:0};const tr={x:80,y:0};const br={x:80,y:100};const bl={x:20,y:100};const cp={x:50,y:50};const sides=["top","right","bottom","left"];const triangles={top:[tl,tr,cp],right:[cp,tr,br],bottom:[bl,cp,br],left:[tl,cp,bl]};const p={x,y};for(const side of sides){const corners=triangles[side];if(LabelImage.pointInTriangle(p,...corners)){return side}}return "center"}static navigateToMarkerIndex(navigateDirection,markers,thisIndex){const thisMarker=markers[thisIndex];const sortedMarkers=markers.map((otherMarker,index)=>{const x=otherMarker.x-thisMarker.x;const y=otherMarker.y-thisMarker.y;const dist=Math.sqrt(x**2+y**2);return {index,dist,dir:{x:dist!==0?x/dist:0,y:dist!==0?y/dist:0}}}).filter(marker=>{if(marker.index===thisIndex){return false}return markers[marker.index].showCorrectness!=="correct"}).sort((a,b)=>{const distA=Math.round(a.dist*(navigateDirection.x*a.dir.x+navigateDirection.y*a.dir.y));const distB=Math.round(b.dist*(navigateDirection.x*b.dir.x+navigateDirection.y*b.dir.y));let dirA;let dirB;if(navigateDirection.x>0){dirA=a.dir.x>0&&distA!==0;dirB=b.dir.x>0&&distB!==0;}else if(navigateDirection.x<0){dirA=a.dir.x<0&&distA!==0;dirB=b.dir.x<0&&distB!==0;}else if(navigateDirection.y>0){dirA=a.dir.y>0&&distA!==0;dirB=b.dir.y>0&&distB!==0;}else if(navigateDirection.y<0){dirA=a.dir.y<0&&distA!==0;dirB=b.dir.y<0&&distB!==0;}if(dirA!==dirB){if(dirA){return -1}return 1}return distA-distB});return sortedMarkers.length>0?sortedMarkers[0].index:thisIndex}componentDidMount(){this.props.analytics?.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"label-image",widgetId:this.props.widgetId}});this._mounted=true;}componentWillUnmount(){this._mounted=false;}getPromptJSON(){return getPromptJSON$a(this.props)}handleMarkerChange(index,marker){const{userInput,handleUserInput}=this.props;const updatedUserInput=[...userInput.markers.slice(0,index),{label:marker.label,selected:marker.selected},...userInput.markers.slice(index+1)];handleUserInput({markers:updatedUserInput});}activateMarker(index,opened){this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:marker-interacted-with",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:marker-interacted-with:ti",payload:null});const{activeMarkerIndex}=this.state;if(activeMarkerIndex!==index&&opened){this.setState({activeMarkerIndex:index,markersInteracted:true});}else {this.setState({activeMarkerIndex:-1});}}handleMarkerKeyDown(index,e){const{markers}=this.props;if(markers.length<2){return}const directions={ArrowUp:{x:0,y:-1},ArrowRight:{x:1,y:0},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0}};if(!(e.key in directions)){return}const navigateDirection=directions[e.key];e.preventDefault();const marker=this._markers[LabelImage.navigateToMarkerIndex(navigateDirection,markers,index)];if(marker){ReactDOM__namespace.findDOMNode(marker).focus();}}handleAnswerChoicesChangeForMarker(index,selection){const{choices,markers}=this.props;const selected=choices.filter((_,index)=>selection[index]);this.handleMarkerChange(index,{...markers[index],selected:selected.length>0?selected:undefined});}renderMarkers(){const{markers,preferredPopoverDirection,userInput}=this.props;const{markersInteracted,activeMarkerIndex}=this.state;const isNarrowPage=this._mounted&&window.matchMedia(mediaQueries.xsOrSmaller.replace("@media ","")).matches;const isWideImage=this.props.imageWidth/2>this.props.imageHeight;return markers.map((marker,index)=>{const userInputMarker=userInput.markers[index];let side;let markerPosition;if(isNarrowPage||isWideImage){side=marker.y>50?"top":"bottom";markerPosition=marker.y>50?"bottom":"top";}else {markerPosition=LabelImage.imageSideForMarkerPosition(marker.x,marker.y,preferredPopoverDirection);if(markerPosition==="center"){markerPosition="bottom";}side=({left:"right",top:"bottom",right:"left",bottom:"top"})[markerPosition];}const computedSelectedState=getComputedSelectedState(marker,userInputMarker,this.props.reviewMode,this.props.showSolutions);let score;if(isAnswerful(marker)){score=perseusScore.scoreLabelImageMarker(computedSelectedState.selected,marker.answers);}else {score={hasAnswers:false,isCorrect:false};}const shouldShowFeedback=this.props.showSolutions==="all"||this.props.reviewMode;const showCorrectness=shouldShowFeedback&&score.isCorrect?"correct":marker.showCorrectness;const disabled=shouldShowFeedback;const isActiveAnswerChoice=activeMarkerIndex===index;const showAnswerChoice=computedSelectedState.selected&&!this.state.hideAnswers&&!isActiveAnswerChoice;const adjustPillDistance={[`margin${markerPosition.charAt(0).toUpperCase()+markerPosition.slice(1)}`]:10};return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{position:"absolute",left:`${marker.x}%`,top:`${marker.y}%`,zIndex:"unset"},children:jsxRuntimeExports.jsx(AnswerChoices,{choices:this.props.choices.map(choice=>({content:choice,checked:computedSelectedState.selected?computedSelectedState.selected.includes(choice):false})),multipleSelect:this.props.multipleAnswers,onChange:selection=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:choiced-interacted-with",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:choiced-interacted-with:ti",payload:null});this.handleAnswerChoicesChangeForMarker(index,selection);},onToggle:opened=>this.activateMarker(index,opened),disabled:disabled,opener:({opened})=>jsxRuntimeExports.jsx(Clickable__default.default,{role:"button","aria-expanded":opened,children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(Marker,{label:marker.label,showCorrectness:showCorrectness,showSelected:opened,showPulsate:!markersInteracted,ref:node=>this._markers[index]=node,showAnswer:showAnswerChoice,answerSide:side,answerStyles:adjustPillDistance,focused:focused||pressed,hovered:hovered,selected:computedSelectedState.selected})},`marker-${marker.x}.${marker.y}`)},`answers-${marker.x}.${marker.y}`)},index)})}renderInstructions(){const{apiOptions:{isMobile},choices,multipleAnswers,hideChoicesFromInstructions:hideChoices}=this.props;const{strings}=this.context;const promptString=isMobile?multipleAnswers?strings.tapMultiple:strings.tapSingle:multipleAnswers?strings.clickMultiple:strings.clickSingle;const choicesString=strings.choices;return jsxRuntimeExports.jsxs("div",{className:classNames__default.default("perseus-label-image-widget-instructions",aphrodite.css(styles$a.instructions)),children:[jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$a.instructionsCaption),children:[promptString," ",!hideChoices&&choicesString]}),!hideChoices&&jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$a.instructionsChoices),children:choices.map((choice,index)=>jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$a.instructionsChoice),children:jsxRuntimeExports.jsx(Renderer,{content:choice,strings:strings})},index))})]})}getSerializedState(){const{userInput,markers,...rest}=this.props;return {...rest,markers:markers.map((marker,index)=>({...marker,selected:userInput.markers[index].selected}))}}render(){const{imageAlt,imageUrl,imageWidth,imageHeight}=this.props;const{activeMarkerIndex}=this.state;return jsxRuntimeExports.jsxs("div",{children:[this.renderInstructions(),jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$a.markersCanvas),style:{maxWidth:imageWidth,maxHeight:imageHeight},children:[jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$a.imageContainer,activeMarkerIndex!==-1&&styles$a.imageInteractionDisabled),children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{alt:imageAlt,src:imageUrl,width:imageWidth,height:imageHeight,setAssetStatus:setAssetStatus,allowZoom:true})})}),this.renderMarkers()]}),jsxRuntimeExports.jsx(HideAnswersToggle,{areAnswersHidden:this.state.hideAnswers,onChange:hideAnswers=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:toggle-answers-hidden",payload:null});this.props.analytics?.onAnalyticsEvent({type:"perseus:label-image:toggle-answers-hidden:ti",payload:null});this.setState({hideAnswers});}})]})}constructor(props){super(props),this._mounted=false;this._markers=[];this.state={activeMarkerIndex:-1,markersInteracted:false,hideAnswers:false};}}LabelImage.contextType=PerseusI18nContext;const LabelImageWithDependencies=React__namespace.forwardRef((props,ref)=>{const deps=useDependencies();return jsxRuntimeExports.jsx(LabelImage,{ref:ref,analytics:deps.analytics,...props})});function getStartUserInput$7(options){return {markers:options.markers.map(m=>({label:m.label}))}}function getUserInputFromSerializedState$7(serializedState){return {markers:serializedState.markers.map(m=>({label:m.label,selected:m.selected}))}}function getCorrectUserInput$3(options){return {markers:options.markers.map(marker=>({label:marker.label,selected:marker.answers}))}}var LabelImage$1 = {name:"label-image",displayName:"Label Image",widget:LabelImageWithDependencies,isLintable:true,getStartUserInput: getStartUserInput$7,getCorrectUserInput: getCorrectUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$7};const styles$a=aphrodite.StyleSheet.create({instructions:{paddingBottom:16},instructionsCaption:{...bodyXsmallBold,paddingBottom:16},instructionsChoices:{display:"flex",flexWrap:"wrap",margin:"-8px 0"},instructionsChoice:{display:"flex",alignItems:"center",margin:"8px 0",":not(:last-child)":{"::after":{content:"''",display:"inline-block",position:"relative",width:2,height:2,marginLeft:5,marginRight:5,background:wonderBlocksTokens.semanticColor.core.border.neutral.default,borderRadius:2}}},markersCanvas:{position:"relative"},imageContainer:{display:"flex"},imageInteractionDisabled:{pointerEvents:"none"}});
2076
2076
 
2077
- const addOffsetParentScroll=($el,position)=>{const $offsetParent=$el.offsetParent();return {top:position.top+$offsetParent.scrollTop(),left:position.left+$offsetParent.scrollLeft()}};class Placeholder extends React__namespace.Component{render(){const{layout}=this.props;const className=aphrodite.css(styles$8.card,styles$8.placeholder,layout==="horizontal"&&styles$8.horizontalCard);const style={width:this.props.width,height:this.props.height};if(this.props.margin!=null){style.margin=this.props.margin;}return jsxRuntimeExports.jsx("li",{className:className,style:style})}}class Draggable extends React__namespace.Component{componentDidMount(){this._mounted=true;this.isMouseMoveUpBound=false;document.addEventListener("touchmove",this.onMouseMove,Util.supportsPassiveEvents()?{passive:false}:false);}componentDidUpdate(prevProps){if(this.props.state===prevProps.state){return}if(this.props.state==="animating"&&this.props.endPosition){const current=this.getCurrentPosition();const duration=15*Math.sqrt(Math.sqrt(Math.pow(this.props.endPosition.left-current.left,2)+Math.pow(this.props.endPosition.top-current.top,2)));$__default.default(ReactDOM__namespace.default.findDOMNode(this)).animate(this.props.endPosition,{duration:Math.max(duration,1),complete:this.props.onAnimationEnd});}else if(this.props.state==="static"){$__default.default(ReactDOM__namespace.default.findDOMNode(this)).finish();}}componentWillUnmount(){this._mounted=false;if(this.isMouseMoveUpBound){this.unbindMouseMoveUp();}if(this.animationFrameRequest){cancelAnimationFrame(this.animationFrameRequest);}document.removeEventListener("touchmove",this.onMouseMove);}render(){const{includePadding,layout,state:type}=this.props;let className=aphrodite.css(styles$8.card,styles$8.draggable,layout==="horizontal"&&styles$8.horizontalCard,layout==="vertical"&&styles$8.verticalCard,type==="dragging"&&styles$8.dragging,type==="disabled"&&styles$8.disabled,!includePadding&&styles$8.unpaddedCard)+" "+"perseus-sortable-draggable";if(!includePadding){className+=" perseus-sortable-draggable-unpadded";}const style={position:"static"};if(this.props.state==="dragging"||this.props.state==="animating"){___default.default.extend(style,{position:"absolute"},this.getCurrentPosition());}if(this.props.width){style.width=this.props.width+1;}if(this.props.height){style.height=this.props.height;}if(this.props.margin!=null){style.margin=this.props.margin;}return jsxRuntimeExports.jsx("li",{className:className,style:style,onMouseDown:this.onMouseDown,onTouchStart:this.onMouseDown,onTouchMove:this.onMouseMove,onTouchEnd:this.onMouseUp,onTouchCancel:this.onMouseUp,children:jsxRuntimeExports.jsx(Renderer,{content:this.props.content,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"draggable"),onRender:this.props.onRender,strings:this.context.strings})})}constructor(...args){super(...args),this.animationFrameRequest=null,this.state={startPosition:{left:0,top:0},startMouse:{left:0,top:0},mouse:{left:0,top:0},dragging:false},this.getCurrentPosition=()=>{return {left:this.state.startPosition.left+this.state.mouse.left-this.state.startMouse.left,top:this.state.startPosition.top+this.state.mouse.top-this.state.startMouse.top}},this.bindMouseMoveUp=()=>{this.isMouseMoveUpBound=true;$__default.default(document).on("mousemove",this.onMouseMove);$__default.default(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.isMouseMoveUpBound=false;$__default.default(document).off("mousemove",this.onMouseMove);$__default.default(document).off("mouseup",this.onMouseUp);},this.onMouseDown=event=>{if(this.props.state!=="static"){return}if(!(event.button===0||event.touches!=null&&event.touches.length===1)){return}event.preventDefault();const loc=Util.extractPointerLocation(event);this.animationFrameRequest=requestAnimationFrame(()=>{const $el=$__default.default(ReactDOM__namespace.default.findDOMNode(this));const position=$el.position();const startPosition=addOffsetParentScroll($el,position);if(loc&&this._mounted){this.setState({startPosition,startMouse:loc,mouse:loc,dragging:true},function(){this.bindMouseMoveUp();this.props.onMouseDown();});}});},this.onMouseMove=event=>{const notDragging=this.props.state!=="dragging"||!this.state.dragging;if(notDragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.animationFrameRequest=requestAnimationFrame(()=>{this.setState({mouse:loc},this.props.onMouseMove);});}},this.onMouseUp=event=>{const notDragging=this.props.state!=="dragging"||!this.state.dragging;if(notDragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:false});this.unbindMouseMoveUp();this.props.onMouseUp();}};}}Draggable.contextType=PerseusI18nContext;Draggable.defaultProps={includePadding:true,type:"static",linterContext:PerseusLinter__namespace.linterContextDefault};class Sortable extends React__namespace.Component{static itemsFromProps(props){const state=props.disabled?"disabled":"static";return props.options.map((option,i)=>{return {option:option,key:i,state,width:0,height:0}})}static clearItemMeasurements(items){return items.map(item=>{return {...item,width:0,height:0}})}UNSAFE_componentWillReceiveProps(nextProps){const prevProps=this.props;if(!___default.default.isEqual(nextProps.options,prevProps.options)){this.setState({items:Sortable.itemsFromProps(nextProps)});}else if(nextProps.layout!==prevProps.layout||nextProps.padding!==prevProps.padding||nextProps.disabled!==prevProps.disabled||!___default.default.isEqual(nextProps.constraints,prevProps.constraints)){this.setState({items:Sortable.clearItemMeasurements(this.state.items)});}}componentDidUpdate(){if(this.state.items.length&&!this.state.items[0].width&&!this.state.items[0].height){setTimeout(()=>{this.measureItems();},0);}}measureItems(){let items=[...this.state.items];const $items=___default.default.map(items,function(item){return $__default.default(ReactDOM__namespace.default.findDOMNode(this.refs[item.key]))},this);const widths=___default.default.invoke($items,"outerWidth");const heights=___default.default.invoke($items,"outerHeight");const{constraints,layout}=this.props;let syncWidth=null;if(constraints?.width){syncWidth=___default.default.max(widths.concat(constraints.width));}else if(layout==="vertical"){syncWidth=___default.default.max(widths);}let syncHeight=null;if(constraints?.height){syncHeight=___default.default.max(heights.concat(constraints.height));}else if(layout==="horizontal"){syncHeight=___default.default.max(heights);}items=___default.default.map(items,function(item,i){item.width=syncWidth||widths[i];item.height=syncHeight||heights[i];return item});this.setState({items},()=>{this.props.onMeasure?.({widths:widths,heights:heights});});}onMouseDown(key){const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="dragging";}return item});this.setState({items:items});}moveOptionToIndex(option,index){const{items}=this.state;if(index<0||index>items.length){throw new Error(`index ${index} out of bounds`)}const nextItems=___default.default.clone(items);const item=items.filter(item=>{return item.option===option})[0];if(item==null){throw new Error(`option ${option} not found`)}const currentIndex=items.findIndex(i=>{return i.key===item.key});nextItems.splice(currentIndex,1);nextItems.splice(index,0,item);this.setState({items:nextItems},()=>{this.props.onChange?.({});});}onMouseMove(key){const $draggable=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs[key]));const $sortable=$__default.default(ReactDOM__namespace.default.findDOMNode(this));const items=___default.default.clone(this.state.items);const item=___default.default.findWhere(this.state.items,{key:key});const margin=this.props.margin||0;const currentIndex=___default.default.indexOf(items,item);let newIndex=0;items.splice(currentIndex,1);if(this.props.layout==="horizontal"){const midWidth=$draggable.offset().left-$sortable.offset().left;let sumWidth=0;let cardWidth;___default.default.each(items,function(item){cardWidth=item.width;if(midWidth>sumWidth+cardWidth/2){newIndex+=1;}sumWidth+=cardWidth+margin;});}else {const midHeight=$draggable.offset().top-$sortable.offset().top;let sumHeight=0;let cardHeight;___default.default.each(items,function(item){cardHeight=item.height;if(midHeight>sumHeight+cardHeight/2){newIndex+=1;}sumHeight+=cardHeight+margin;});}if(newIndex!==currentIndex){items.splice(newIndex,0,item);this.setState({items:items});}}onMouseUp(key){const nextAnimationFrame=requestAnimationFrame(()=>{const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="animating";const $placeholder=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs["placeholder_"+key]));const position=$placeholder.position();const endPosition=addOffsetParentScroll($placeholder,position);item.endPosition=endPosition;}return item},this);this.setState({items:items},()=>{this.props.onChange?.({});});});this.animationFrameRequest=nextAnimationFrame;}onAnimationEnd(key){const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="static";}return item});this.setState({items:items});}getOptions(){return ___default.default.pluck(this.state.items,"option")}render(){if(this.props.waitForTexRendererToLoad&&!this.state.texRendererLoaded){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{}),jsxRuntimeExports.jsx("div",{style:{display:"none"},children:jsxRuntimeExports.jsx(TeX,{onRender:()=>this.setState({texRendererLoaded:true}),children:"1"})})]})}const cards=[];const{layout}=this.props;const className=aphrodite.css(styles$8.sortable)+" perseus-sortable";const syncWidth=this.props.constraints?.width||layout==="vertical";const syncHeight=this.props.constraints?.height||layout==="horizontal";___default.default.each(this.state.items,function(item,i,items){const isLast=i===items.length-1;const isStatic=item.state==="static"||item.state==="disabled";let margin;if(this.props.layout==="horizontal"){margin="0 "+this.props.margin+"px 0 0";}else if(this.props.layout==="vertical"){margin="0 0 "+this.props.margin+"px 0";}cards.push(jsxRuntimeExports.jsx(Draggable,{content:item.option,state:item.state,ref:item.key,width:syncWidth?item.width:undefined,height:syncHeight?item.height:undefined,layout:layout,includePadding:this.props.padding,margin:isLast&&isStatic?0:margin,endPosition:item.endPosition,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"sortable"),onRender:this.remeasureItems,onMouseDown:this.onMouseDown.bind(this,item.key),onMouseMove:this.onMouseMove.bind(this,item.key),onMouseUp:this.onMouseUp.bind(this,item.key),onTouchMove:this.onMouseMove.bind(this,item.key),onTouchEnd:this.onMouseUp.bind(this,item.key),onTouchCancel:this.onMouseUp.bind(this,item.key),onAnimationEnd:this.onAnimationEnd.bind(this,item.key)},item.key));if(item.state==="dragging"||item.state==="animating"){cards.push(jsxRuntimeExports.jsx(Placeholder,{ref:"placeholder_"+item.key,width:item.width,height:item.height,layout:layout,margin:isLast?0:margin},"placeholder_"+item.key));}},this);return jsxRuntimeExports.jsx("ul",{className:className,children:cards})}constructor(props){super(props),this.remeasureItems=___default.default.debounce(()=>{this.setState({items:Sortable.clearItemMeasurements(this.state.items)});},20);this.state={items:Sortable.itemsFromProps(this.props),texRendererLoaded:false};}}Sortable.defaultProps={layout:"horizontal",padding:true,disabled:false,constraints:{},onMeasure:function(){},margin:5,onChange:function(){},linterContext:PerseusLinter__namespace.linterContextDefault,waitForTexRendererToLoad:true};const styles$8=aphrodite.StyleSheet.create({sortable:{boxSizing:"border-box",float:"left",padding:0,margin:0},card:{boxSizing:"border-box",background:wonderBlocksTokens.semanticColor.core.background.base.default,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,borderRadius:4,cursor:"pointer",minWidth:25,minHeight:44,padding:10,listStyleType:"none",userSelect:"none",touchAction:"none"},placeholder:{background:wonderBlocksTokens.semanticColor.core.background.neutral.subtle,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`},draggable:{textAlign:"center"},horizontalCard:{float:"left",cursor:"ew-resize"},verticalCard:{maxWidth:"100%",cursor:"ns-resize"},unpaddedCard:{padding:0},dragging:{background:wonderBlocksTokens.semanticColor.core.background.instructive.subtle,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`,opacity:.8},disabled:{backgroundColor:"inherit",border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.disabled.subtle}`,cursor:"default"}});
2077
+ const addOffsetParentScroll=($el,position)=>{const $offsetParent=$el.offsetParent();return {top:position.top+$offsetParent.scrollTop(),left:position.left+$offsetParent.scrollLeft()}};class Placeholder extends React__namespace.Component{render(){const{layout}=this.props;const className=aphrodite.css(styles$9.card,styles$9.placeholder,layout==="horizontal"&&styles$9.horizontalCard);const style={width:this.props.width,height:this.props.height};if(this.props.margin!=null){style.margin=this.props.margin;}return jsxRuntimeExports.jsx("li",{className:className,style:style})}}class Draggable extends React__namespace.Component{componentDidMount(){this._mounted=true;this.isMouseMoveUpBound=false;document.addEventListener("touchmove",this.onMouseMove,Util.supportsPassiveEvents()?{passive:false}:false);}componentDidUpdate(prevProps){if(this.props.state===prevProps.state){return}if(this.props.state==="animating"&&this.props.endPosition){const current=this.getCurrentPosition();const duration=15*Math.sqrt(Math.sqrt(Math.pow(this.props.endPosition.left-current.left,2)+Math.pow(this.props.endPosition.top-current.top,2)));$__default.default(ReactDOM__namespace.default.findDOMNode(this)).animate(this.props.endPosition,{duration:Math.max(duration,1),complete:this.props.onAnimationEnd});}else if(this.props.state==="static"){$__default.default(ReactDOM__namespace.default.findDOMNode(this)).finish();}}componentWillUnmount(){this._mounted=false;if(this.isMouseMoveUpBound){this.unbindMouseMoveUp();}if(this.animationFrameRequest){cancelAnimationFrame(this.animationFrameRequest);}document.removeEventListener("touchmove",this.onMouseMove);}render(){const{includePadding,layout,state:type}=this.props;let className=aphrodite.css(styles$9.card,styles$9.draggable,layout==="horizontal"&&styles$9.horizontalCard,layout==="vertical"&&styles$9.verticalCard,type==="dragging"&&styles$9.dragging,type==="disabled"&&styles$9.disabled,!includePadding&&styles$9.unpaddedCard)+" "+"perseus-sortable-draggable";if(!includePadding){className+=" perseus-sortable-draggable-unpadded";}const style={position:"static"};if(this.props.state==="dragging"||this.props.state==="animating"){___default.default.extend(style,{position:"absolute"},this.getCurrentPosition());}if(this.props.width){style.width=this.props.width+1;}if(this.props.height){style.height=this.props.height;}if(this.props.margin!=null){style.margin=this.props.margin;}return jsxRuntimeExports.jsx("li",{className:className,style:style,onMouseDown:this.onMouseDown,onTouchStart:this.onMouseDown,onTouchMove:this.onMouseMove,onTouchEnd:this.onMouseUp,onTouchCancel:this.onMouseUp,children:jsxRuntimeExports.jsx(Renderer,{content:this.props.content,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"draggable"),onRender:this.props.onRender,strings:this.context.strings})})}constructor(...args){super(...args),this.animationFrameRequest=null,this.state={startPosition:{left:0,top:0},startMouse:{left:0,top:0},mouse:{left:0,top:0},dragging:false},this.getCurrentPosition=()=>{return {left:this.state.startPosition.left+this.state.mouse.left-this.state.startMouse.left,top:this.state.startPosition.top+this.state.mouse.top-this.state.startMouse.top}},this.bindMouseMoveUp=()=>{this.isMouseMoveUpBound=true;$__default.default(document).on("mousemove",this.onMouseMove);$__default.default(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.isMouseMoveUpBound=false;$__default.default(document).off("mousemove",this.onMouseMove);$__default.default(document).off("mouseup",this.onMouseUp);},this.onMouseDown=event=>{if(this.props.state!=="static"){return}if(!(event.button===0||event.touches!=null&&event.touches.length===1)){return}event.preventDefault();const loc=Util.extractPointerLocation(event);this.animationFrameRequest=requestAnimationFrame(()=>{const $el=$__default.default(ReactDOM__namespace.default.findDOMNode(this));const position=$el.position();const startPosition=addOffsetParentScroll($el,position);if(loc&&this._mounted){this.setState({startPosition,startMouse:loc,mouse:loc,dragging:true},function(){this.bindMouseMoveUp();this.props.onMouseDown();});}});},this.onMouseMove=event=>{const notDragging=this.props.state!=="dragging"||!this.state.dragging;if(notDragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.animationFrameRequest=requestAnimationFrame(()=>{this.setState({mouse:loc},this.props.onMouseMove);});}},this.onMouseUp=event=>{const notDragging=this.props.state!=="dragging"||!this.state.dragging;if(notDragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:false});this.unbindMouseMoveUp();this.props.onMouseUp();}};}}Draggable.contextType=PerseusI18nContext;Draggable.defaultProps={includePadding:true,type:"static",linterContext:PerseusLinter__namespace.linterContextDefault};class Sortable extends React__namespace.Component{static itemsFromProps(props){const state=props.disabled?"disabled":"static";return props.options.map((option,i)=>{return {option:option,key:i,state,width:0,height:0}})}static clearItemMeasurements(items){return items.map(item=>{return {...item,width:0,height:0}})}UNSAFE_componentWillReceiveProps(nextProps){const prevProps=this.props;if(!___default.default.isEqual(nextProps.options,prevProps.options)){this.setState({items:Sortable.itemsFromProps(nextProps)});}else if(nextProps.layout!==prevProps.layout||nextProps.padding!==prevProps.padding||nextProps.disabled!==prevProps.disabled||!___default.default.isEqual(nextProps.constraints,prevProps.constraints)){this.setState({items:Sortable.clearItemMeasurements(this.state.items)});}}componentDidUpdate(){if(this.state.items.length&&!this.state.items[0].width&&!this.state.items[0].height){setTimeout(()=>{this.measureItems();},0);}}measureItems(){let items=[...this.state.items];const $items=___default.default.map(items,function(item){return $__default.default(ReactDOM__namespace.default.findDOMNode(this.refs[item.key]))},this);const widths=___default.default.invoke($items,"outerWidth");const heights=___default.default.invoke($items,"outerHeight");const{constraints,layout}=this.props;let syncWidth=null;if(constraints?.width){syncWidth=___default.default.max(widths.concat(constraints.width));}else if(layout==="vertical"){syncWidth=___default.default.max(widths);}let syncHeight=null;if(constraints?.height){syncHeight=___default.default.max(heights.concat(constraints.height));}else if(layout==="horizontal"){syncHeight=___default.default.max(heights);}items=___default.default.map(items,function(item,i){item.width=syncWidth||widths[i];item.height=syncHeight||heights[i];return item});this.setState({items},()=>{this.props.onMeasure?.({widths:widths,heights:heights});});}onMouseDown(key){const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="dragging";}return item});this.setState({items:items});}moveOptionToIndex(option,index){const{items}=this.state;if(index<0||index>items.length){throw new Error(`index ${index} out of bounds`)}const nextItems=___default.default.clone(items);const item=items.filter(item=>{return item.option===option})[0];if(item==null){throw new Error(`option ${option} not found`)}const currentIndex=items.findIndex(i=>{return i.key===item.key});nextItems.splice(currentIndex,1);nextItems.splice(index,0,item);this.setState({items:nextItems},()=>{this.props.onChange?.({});});}onMouseMove(key){const $draggable=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs[key]));const $sortable=$__default.default(ReactDOM__namespace.default.findDOMNode(this));const items=___default.default.clone(this.state.items);const item=___default.default.findWhere(this.state.items,{key:key});const margin=this.props.margin||0;const currentIndex=___default.default.indexOf(items,item);let newIndex=0;items.splice(currentIndex,1);if(this.props.layout==="horizontal"){const midWidth=$draggable.offset().left-$sortable.offset().left;let sumWidth=0;let cardWidth;___default.default.each(items,function(item){cardWidth=item.width;if(midWidth>sumWidth+cardWidth/2){newIndex+=1;}sumWidth+=cardWidth+margin;});}else {const midHeight=$draggable.offset().top-$sortable.offset().top;let sumHeight=0;let cardHeight;___default.default.each(items,function(item){cardHeight=item.height;if(midHeight>sumHeight+cardHeight/2){newIndex+=1;}sumHeight+=cardHeight+margin;});}if(newIndex!==currentIndex){items.splice(newIndex,0,item);this.setState({items:items});}}onMouseUp(key){const nextAnimationFrame=requestAnimationFrame(()=>{const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="animating";const $placeholder=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs["placeholder_"+key]));const position=$placeholder.position();const endPosition=addOffsetParentScroll($placeholder,position);item.endPosition=endPosition;}return item},this);this.setState({items:items},()=>{this.props.onChange?.({});});});this.animationFrameRequest=nextAnimationFrame;}onAnimationEnd(key){const items=___default.default.map(this.state.items,function(item){if(item.key===key){item.state="static";}return item});this.setState({items:items});}getOptions(){return ___default.default.pluck(this.state.items,"option")}render(){if(this.props.waitForTexRendererToLoad&&!this.state.texRendererLoaded){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{}),jsxRuntimeExports.jsx("div",{style:{display:"none"},children:jsxRuntimeExports.jsx(TeX,{onRender:()=>this.setState({texRendererLoaded:true}),children:"1"})})]})}const cards=[];const{layout}=this.props;const className=aphrodite.css(styles$9.sortable)+" perseus-sortable";const syncWidth=this.props.constraints?.width||layout==="vertical";const syncHeight=this.props.constraints?.height||layout==="horizontal";___default.default.each(this.state.items,function(item,i,items){const isLast=i===items.length-1;const isStatic=item.state==="static"||item.state==="disabled";let margin;if(this.props.layout==="horizontal"){margin="0 "+this.props.margin+"px 0 0";}else if(this.props.layout==="vertical"){margin="0 0 "+this.props.margin+"px 0";}cards.push(jsxRuntimeExports.jsx(Draggable,{content:item.option,state:item.state,ref:item.key,width:syncWidth?item.width:undefined,height:syncHeight?item.height:undefined,layout:layout,includePadding:this.props.padding,margin:isLast&&isStatic?0:margin,endPosition:item.endPosition,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"sortable"),onRender:this.remeasureItems,onMouseDown:this.onMouseDown.bind(this,item.key),onMouseMove:this.onMouseMove.bind(this,item.key),onMouseUp:this.onMouseUp.bind(this,item.key),onTouchMove:this.onMouseMove.bind(this,item.key),onTouchEnd:this.onMouseUp.bind(this,item.key),onTouchCancel:this.onMouseUp.bind(this,item.key),onAnimationEnd:this.onAnimationEnd.bind(this,item.key)},item.key));if(item.state==="dragging"||item.state==="animating"){cards.push(jsxRuntimeExports.jsx(Placeholder,{ref:"placeholder_"+item.key,width:item.width,height:item.height,layout:layout,margin:isLast?0:margin},"placeholder_"+item.key));}},this);return jsxRuntimeExports.jsx("ul",{className:className,children:cards})}constructor(props){super(props),this.remeasureItems=___default.default.debounce(()=>{this.setState({items:Sortable.clearItemMeasurements(this.state.items)});},20);this.state={items:Sortable.itemsFromProps(this.props),texRendererLoaded:false};}}Sortable.defaultProps={layout:"horizontal",padding:true,disabled:false,constraints:{},onMeasure:function(){},margin:5,onChange:function(){},linterContext:PerseusLinter__namespace.linterContextDefault,waitForTexRendererToLoad:true};const styles$9=aphrodite.StyleSheet.create({sortable:{boxSizing:"border-box",float:"left",padding:0,margin:0},card:{boxSizing:"border-box",background:wonderBlocksTokens.semanticColor.core.background.base.default,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,borderRadius:4,cursor:"pointer",minWidth:25,minHeight:44,padding:10,listStyleType:"none",userSelect:"none",touchAction:"none"},placeholder:{background:wonderBlocksTokens.semanticColor.core.background.neutral.subtle,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`},draggable:{textAlign:"center"},horizontalCard:{float:"left",cursor:"ew-resize"},verticalCard:{maxWidth:"100%",cursor:"ns-resize"},unpaddedCard:{padding:0},dragging:{background:wonderBlocksTokens.semanticColor.core.background.instructive.subtle,border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.instructive.default}`,opacity:.8},disabled:{backgroundColor:"inherit",border:`${wonderBlocksTokens.border.width.thin} solid ${wonderBlocksTokens.semanticColor.core.border.disabled.subtle}`,cursor:"default"}});
2078
2078
 
2079
2079
  const getPromptJSON$9=widgetData=>{const{userInput}=widgetData;return {type:"matcher",options:{labels:widgetData.labels,left:widgetData.left,right:widgetData.right,orderMatters:widgetData.orderMatters},userInput:{left:userInput.left,right:userInput.right}}};
2080
2080
 
2081
- const HACKY_CSS_CLASSNAME="perseus-widget-matcher";class Matcher extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"matcher",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$9(this.props)}render(){if(!this.state.texRendererLoaded){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{}),jsxRuntimeExports.jsx("div",{style:{display:"none"},children:jsxRuntimeExports.jsx(TeX,{onRender:()=>{this.setState({texRendererLoaded:true});},children:"1"})})]})}const showLabels=___default.default.any(this.props.labels);const constraints={height:___default.default.max([this.state.leftHeight,this.state.rightHeight])};const cellMarginPx=this.props.apiOptions.isMobile?8:5;return jsxRuntimeExports.jsx("table",{className:aphrodite.css(styles$7.widget)+" "+HACKY_CSS_CLASSNAME,children:jsxRuntimeExports.jsxs("tbody",{children:[showLabels&&jsxRuntimeExports.jsxs("tr",{className:aphrodite.css(styles$7.row),children:[jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$7.column,styles$7.columnLabel),children:jsxRuntimeExports.jsx(Renderer,{content:this.props.labels[0]||"...",linterContext:this.props.linterContext,strings:this.context.strings})}),jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$7.column,styles$7.columnRight,styles$7.columnLabel),children:jsxRuntimeExports.jsx(Renderer,{content:this.props.labels[1]||"...",linterContext:this.props.linterContext,strings:this.context.strings})})]}),jsxRuntimeExports.jsxs("tr",{className:aphrodite.css(styles$7.row),children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$7.column),children:jsxRuntimeExports.jsx(Sortable,{options:this.props.userInput.left,layout:"vertical",padding:this.props.padding,disabled:!this.props.orderMatters,constraints:constraints,onMeasure:this.onMeasureLeft,onChange:this.changeAndTrack,margin:cellMarginPx,linterContext:this.props.linterContext,ref:"left"})}),jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$7.column,styles$7.columnRight),children:jsxRuntimeExports.jsx(Sortable,{options:this.props.userInput.right,layout:"vertical",padding:this.props.padding,constraints:constraints,onMeasure:this.onMeasureRight,onChange:this.changeAndTrack,margin:cellMarginPx,linterContext:this.props.linterContext,ref:"right"})})]})]})})}constructor(...args){super(...args),this.state={leftHeight:0,rightHeight:0,texRendererLoaded:false},this.changeAndTrack=()=>{const nextUserInput=this._getUserInputFromSortable();this.props.handleUserInput(nextUserInput);this.props.trackInteraction();},this.onMeasureLeft=dimensions=>{const height=___default.default.max(dimensions.heights);this.setState({leftHeight:height});},this.onMeasureRight=dimensions=>{const height=___default.default.max(dimensions.heights);this.setState({rightHeight:height});},this._getUserInputFromSortable=()=>{if(!this.state.texRendererLoaded){return {left:[],right:[]}}return {left:this.refs.left.getOptions(),right:this.refs.right.getOptions()}},this.moveLeftOptionToIndex=(option,index)=>{this.refs.left.moveOptionToIndex(option,index);},this.moveRightOptionToIndex=(option,index)=>{this.refs.right.moveOptionToIndex(option,index);};}}Matcher.contextType=PerseusI18nContext;Matcher.defaultProps={labels:["",""],orderMatters:false,padding:true,problemNum:0,linterContext:PerseusLinter.linterContextDefault,userInput:{left:[],right:[]}};function getStartUserInput$6(options,problemNum){const shuffled=perseusCore.shuffleMatcher(options,problemNum);return shuffled}function getUserInputFromSerializedState$6(serializedState){return {left:serializedState.left,right:serializedState.right}}const WrappedMatcher=withDependencies(Matcher);var Matcher$1 = {name:"matcher",displayName:"Matcher (two column)",widget:WrappedMatcher,isLintable:true,getStartUserInput: getStartUserInput$6,getUserInputFromSerializedState: getUserInputFromSerializedState$6};const padding=5;const border=`var(--wb-border-width-thin) solid var(--wb-semanticColor-core-border-neutral-strong)`;const styles$7=aphrodite.StyleSheet.create({widget:{paddingTop:padding,maxWidth:"100%",minWidth:"auto"},row:{border:0},column:{padding:0,border:0},columnRight:{borderLeft:border},columnLabel:{fontWeight:"inherit",borderBottom:border,padding:`0 ${padding}px ${padding}px ${padding}px`,textAlign:"center"}});
2081
+ const HACKY_CSS_CLASSNAME="perseus-widget-matcher";class Matcher extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"matcher",widgetId:this.props.widgetId}});}getPromptJSON(){return getPromptJSON$9(this.props)}render(){if(!this.state.texRendererLoaded){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksProgressSpinner.CircularSpinner,{}),jsxRuntimeExports.jsx("div",{style:{display:"none"},children:jsxRuntimeExports.jsx(TeX,{onRender:()=>{this.setState({texRendererLoaded:true});},children:"1"})})]})}const showLabels=___default.default.any(this.props.labels);const constraints={height:___default.default.max([this.state.leftHeight,this.state.rightHeight])};const cellMarginPx=this.props.apiOptions.isMobile?8:5;return jsxRuntimeExports.jsx("table",{className:aphrodite.css(styles$8.widget)+" "+HACKY_CSS_CLASSNAME,children:jsxRuntimeExports.jsxs("tbody",{children:[showLabels&&jsxRuntimeExports.jsxs("tr",{className:aphrodite.css(styles$8.row),children:[jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$8.column,styles$8.columnLabel),children:jsxRuntimeExports.jsx(Renderer,{content:this.props.labels[0]||"...",linterContext:this.props.linterContext,strings:this.context.strings})}),jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$8.column,styles$8.columnRight,styles$8.columnLabel),children:jsxRuntimeExports.jsx(Renderer,{content:this.props.labels[1]||"...",linterContext:this.props.linterContext,strings:this.context.strings})})]}),jsxRuntimeExports.jsxs("tr",{className:aphrodite.css(styles$8.row),children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$8.column),children:jsxRuntimeExports.jsx(Sortable,{options:this.props.userInput.left,layout:"vertical",padding:this.props.padding,disabled:!this.props.orderMatters,constraints:constraints,onMeasure:this.onMeasureLeft,onChange:this.changeAndTrack,margin:cellMarginPx,linterContext:this.props.linterContext,ref:"left"})}),jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$8.column,styles$8.columnRight),children:jsxRuntimeExports.jsx(Sortable,{options:this.props.userInput.right,layout:"vertical",padding:this.props.padding,constraints:constraints,onMeasure:this.onMeasureRight,onChange:this.changeAndTrack,margin:cellMarginPx,linterContext:this.props.linterContext,ref:"right"})})]})]})})}constructor(...args){super(...args),this.state={leftHeight:0,rightHeight:0,texRendererLoaded:false},this.changeAndTrack=()=>{const nextUserInput=this._getUserInputFromSortable();this.props.handleUserInput(nextUserInput);this.props.trackInteraction();},this.onMeasureLeft=dimensions=>{const height=___default.default.max(dimensions.heights);this.setState({leftHeight:height});},this.onMeasureRight=dimensions=>{const height=___default.default.max(dimensions.heights);this.setState({rightHeight:height});},this._getUserInputFromSortable=()=>{if(!this.state.texRendererLoaded){return {left:[],right:[]}}return {left:this.refs.left.getOptions(),right:this.refs.right.getOptions()}},this.moveLeftOptionToIndex=(option,index)=>{this.refs.left.moveOptionToIndex(option,index);},this.moveRightOptionToIndex=(option,index)=>{this.refs.right.moveOptionToIndex(option,index);};}}Matcher.contextType=PerseusI18nContext;Matcher.defaultProps={labels:["",""],orderMatters:false,padding:true,problemNum:0,linterContext:PerseusLinter.linterContextDefault,userInput:{left:[],right:[]}};function getStartUserInput$6(options,problemNum){const shuffled=perseusCore.shuffleMatcher(options,problemNum);return shuffled}function getUserInputFromSerializedState$6(serializedState){return {left:serializedState.left,right:serializedState.right}}const WrappedMatcher=withDependencies(Matcher);var Matcher$1 = {name:"matcher",displayName:"Matcher (two column)",widget:WrappedMatcher,isLintable:true,getStartUserInput: getStartUserInput$6,getUserInputFromSerializedState: getUserInputFromSerializedState$6};const padding=5;const border=`var(--wb-border-width-thin) solid var(--wb-semanticColor-core-border-neutral-strong)`;const styles$8=aphrodite.StyleSheet.create({widget:{paddingTop:padding,maxWidth:"100%",minWidth:"auto"},row:{border:0},column:{padding:0,border:0},columnRight:{borderLeft:border},columnLabel:{fontWeight:"inherit",borderBottom:border,padding:`0 ${padding}px ${padding}px ${padding}px`,textAlign:"center"}});
2082
2082
 
2083
2083
  const getPromptJSON$8=widgetData=>{return {type:"matrix",options:{height:widgetData.matrixBoardSize[0],width:widgetData.matrixBoardSize[1]},userInput:{answerRows:widgetData.userInput.answers}}};
2084
2084
 
@@ -2086,9 +2086,9 @@ const{assert: assert$2}=InteractiveUtil;const NORMAL_DIMENSIONS={INPUT_MARGIN:3,
2086
2086
 
2087
2087
  const getPromptJSON$7=()=>{return getUnsupportedPromptJSON("measurer")};
2088
2088
 
2089
- const defaultImage={url:null,top:0,left:0};class Measurer extends React__namespace.Component{componentDidMount(){this.setupGraphie();}componentDidUpdate(prevProps){const shouldSetupGraphie=___default.default.any(["box","showProtractor","showRuler","rulerLabel","rulerTicks","rulerPixels","rulerLength"],prop=>{return prevProps[prop]!==this.props[prop]},this);if(shouldSetupGraphie){this.setupGraphie();}}setupGraphie(){const graphieDiv=ReactDOM__namespace.default.findDOMNode(this.refs.graphieDiv);$__default.default(graphieDiv).empty();const graphie=this.graphie=GraphUtils.createGraphie(graphieDiv);const scale=[40,40];const range=[[0,this.props.box[0]/scale[0]],[0,this.props.box[1]/scale[1]]];graphie.init({range:range,scale:scale});graphie.addMouseLayer({allowScratchpad:true,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable});if(this.protractor){this.protractor.remove();}if(this.props.showProtractor){this.protractor=graphie.protractor([this.props.protractorX,this.props.protractorY]);}if(this.ruler){this.ruler.remove();}if(this.props.showRuler){this.ruler=graphie.ruler({center:[(range[0][0]+range[0][1])/2,(range[1][0]+range[1][1])/2],label:this.props.rulerLabel,pixelsPerUnit:this.props.rulerPixels,ticksPerUnit:this.props.rulerTicks,units:this.props.rulerLength});}}getPromptJSON(){return getPromptJSON$7()}render(){const image=___default.default.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget perseus-widget-measurer "+"graphie-container blank-background",style:{width:this.props.box[0],height:this.props.box[1]},children:[image.url&&jsxRuntimeExports.jsx("div",{style:{position:"relative",top:image.top,left:image.left},children:jsxRuntimeExports.jsx(SvgImage,{src:image.url,allowZoom:false})}),jsxRuntimeExports.jsx("div",{className:"graphie",ref:"graphieDiv"})]})}constructor(...args){super(...args),this.isWidget=true,this.state={};}}Measurer.defaultProps={box:[480,480],image:defaultImage,showProtractor:true,protractorX:7.5,protractorY:.5,showRuler:false,rulerLabel:"",rulerTicks:10,rulerPixels:40,rulerLength:10};var Measurer$1 = {name:"measurer",displayName:"Measurer",hidden:true,widget:Measurer,version:perseusCore.measurerLogic.version};
2089
+ const defaultImage={url:null,top:0,left:0};class Measurer extends React__namespace.Component{componentDidMount(){this.setupGraphie();}componentDidUpdate(prevProps){const shouldSetupGraphie=___default.default.any(["box","showProtractor","showRuler","rulerLabel","rulerTicks","rulerPixels","rulerLength"],prop=>{return prevProps[prop]!==this.props[prop]},this);if(shouldSetupGraphie){this.setupGraphie();}}setupGraphie(){const graphieDiv=ReactDOM__namespace.default.findDOMNode(this.refs.graphieDiv);$__default.default(graphieDiv).empty();const graphie=this.graphie=GraphUtils.createGraphie(graphieDiv);const scale=[40,40];const range=[[0,this.props.box[0]/scale[0]],[0,this.props.box[1]/scale[1]]];graphie.init({range:range,scale:scale});graphie.addMouseLayer({allowScratchpad:true});if(this.protractor){this.protractor.remove();}if(this.props.showProtractor){this.protractor=graphie.protractor([this.props.protractorX,this.props.protractorY]);}if(this.ruler){this.ruler.remove();}if(this.props.showRuler){this.ruler=graphie.ruler({center:[(range[0][0]+range[0][1])/2,(range[1][0]+range[1][1])/2],label:this.props.rulerLabel,pixelsPerUnit:this.props.rulerPixels,ticksPerUnit:this.props.rulerTicks,units:this.props.rulerLength});}}getPromptJSON(){return getPromptJSON$7()}render(){const image=___default.default.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget perseus-widget-measurer "+"graphie-container blank-background",style:{width:this.props.box[0],height:this.props.box[1]},children:[image.url&&jsxRuntimeExports.jsx("div",{style:{position:"relative",top:image.top,left:image.left},children:jsxRuntimeExports.jsx(SvgImage,{src:image.url,allowZoom:false})}),jsxRuntimeExports.jsx("div",{className:"graphie",ref:"graphieDiv"})]})}constructor(...args){super(...args),this.isWidget=true,this.state={};}}Measurer.defaultProps={box:[480,480],image:defaultImage,showProtractor:true,protractorX:7.5,protractorY:.5,showRuler:false,rulerLabel:"",rulerTicks:10,rulerPixels:40,rulerLength:10};var Measurer$1 = {name:"measurer",displayName:"Measurer",hidden:true,widget:Measurer,version:perseusCore.measurerLogic.version};
2090
2090
 
2091
- function drawText(ctx,item){if(item.value===null){return}ctx.fillStyle=styles$6.fgColor;ctx.font=styles$6.font;ctx.fillText(item.value,item.pos[0]-styles$6.fontSizePx/2+1,item.pos[1]+styles$6.fontSizePx/2);}function drawDoubleLine(ctx,item){let path=new Path2D;ctx.lineWidth=5*styles$6.lineWidth;ctx.strokeStyle=styles$6.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);path=new Path2D;ctx.lineWidth=3*styles$6.lineWidth;ctx.strokeStyle=styles$6.bgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);}function drawTripleLine(ctx,item){let path=new Path2D;ctx.lineWidth=7*styles$6.lineWidth;ctx.strokeStyle=styles$6.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);path=new Path2D;ctx.lineWidth=5*styles$6.lineWidth;ctx.strokeStyle=styles$6.bgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);drawLine(ctx,item);}function drawLine(ctx,item){const path=new Path2D;ctx.lineWidth=styles$6.lineWidth;ctx.strokeStyle=styles$6.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);}const drawingFuncs={text:drawText,"line:single":drawLine,"line:double":drawDoubleLine,"line:triple":drawTripleLine};function drawItem(ctx){return function(item){drawingFuncs[item.type](ctx,item);}}const ordering={"line:single":0,"line:double":0,"line:triple":0,text:1};function compareElements(item0,item1){return ordering[item0.type]-ordering[item1.type]}function draw(ctx,items){items.sort(compareElements).forEach(drawItem(ctx));}const styles$6={bgColor:"rgb(255, 255, 255)",fgColor:"rgb(0, 0, 0)",fontSizePx:12,lineWidth:1,font:"12px sans"};
2091
+ function drawText(ctx,item){if(item.value===null){return}ctx.fillStyle=styles$7.fgColor;ctx.font=styles$7.font;ctx.fillText(item.value,item.pos[0]-styles$7.fontSizePx/2+1,item.pos[1]+styles$7.fontSizePx/2);}function drawDoubleLine(ctx,item){let path=new Path2D;ctx.lineWidth=5*styles$7.lineWidth;ctx.strokeStyle=styles$7.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);path=new Path2D;ctx.lineWidth=3*styles$7.lineWidth;ctx.strokeStyle=styles$7.bgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);}function drawTripleLine(ctx,item){let path=new Path2D;ctx.lineWidth=7*styles$7.lineWidth;ctx.strokeStyle=styles$7.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);path=new Path2D;ctx.lineWidth=5*styles$7.lineWidth;ctx.strokeStyle=styles$7.bgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);drawLine(ctx,item);}function drawLine(ctx,item){const path=new Path2D;ctx.lineWidth=styles$7.lineWidth;ctx.strokeStyle=styles$7.fgColor;path.moveTo(item.startPos[0],item.startPos[1]);path.lineTo(item.endPos[0],item.endPos[1]);ctx.stroke(path);}const drawingFuncs={text:drawText,"line:single":drawLine,"line:double":drawDoubleLine,"line:triple":drawTripleLine};function drawItem(ctx){return function(item){drawingFuncs[item.type](ctx,item);}}const ordering={"line:single":0,"line:double":0,"line:triple":0,text:1};function compareElements(item0,item1){return ordering[item0.type]-ordering[item1.type]}function draw(ctx,items){items.sort(compareElements).forEach(drawItem(ctx));}const styles$7={bgColor:"rgb(255, 255, 255)",fgColor:"rgb(0, 0, 0)",fontSizePx:12,lineWidth:1,font:"12px sans"};
2092
2092
 
2093
2093
  const bondLength=30;function polarAdd(origin,angle,length){const x=origin[0];const y=origin[1];return [x+Math.cos(angle*2*Math.PI/360)*length,y+-1*Math.sin(angle*2*Math.PI/360)*length]}function atomLayout(atom,atoms,bonds,rotationAngle){let textValue=atom.symbol;if(textValue==="C"&&Object.keys(atoms).length!==1){textValue=null;}if(atom.idx==="1,0"){const pos=[0,0];atom.pos=pos;atom.baseAngle=-30+rotationAngle;return {type:"text",value:textValue,pos:pos,idx:atom.idx}}const prevPositionedAtom=atoms[atom.connections.find(function(c){return atoms[c].pos})];const myIndex=prevPositionedAtom.connections.indexOf(atom.idx);let baseAngleIncrement=60;let angleIncrement=120;if(prevPositionedAtom.connections.length===4){angleIncrement=90;baseAngleIncrement=90;}else if(bonds.find(bond=>bond.bondType==="triple"&&bond.to===atom.idx)||bonds.find(bond=>bond.bondType==="triple"&&bond.to===prevPositionedAtom.idx)){angleIncrement=0;baseAngleIncrement=0;}let angle=0;const idxPath=prevPositionedAtom.idx.split(":");const lastAtomIdx=idxPath[idxPath.length-1].split(",")[0];if(parseInt(lastAtomIdx)%2!==0){angle=prevPositionedAtom.baseAngle-(baseAngleIncrement-angleIncrement*myIndex);}else {angle=prevPositionedAtom.baseAngle+(baseAngleIncrement-angleIncrement*myIndex);}const pos=polarAdd(prevPositionedAtom.pos,angle,bondLength);atom.pos=pos;atom.baseAngle=angle;return {type:"text",value:textValue,pos:pos,idx:atom.idx}}function maybeShrinkLines(fromAtom,toAtom){const shrinkFactor=.25;let fromPos=[fromAtom.pos[0],fromAtom.pos[1]];let toPos=[toAtom.pos[0],toAtom.pos[1]];if(fromAtom.symbol!=="C"){fromPos=[toAtom.pos[0]-(1-shrinkFactor)*(toAtom.pos[0]-fromAtom.pos[0]),toAtom.pos[1]-(1-shrinkFactor)*(toAtom.pos[1]-fromAtom.pos[1])];}if(toAtom.symbol!=="C"){toPos=[fromAtom.pos[0]-(1-shrinkFactor)*(fromAtom.pos[0]-toAtom.pos[0]),fromAtom.pos[1]-(1-shrinkFactor)*(fromAtom.pos[1]-toAtom.pos[1])];}return [fromPos,toPos]}function bondLayout(bond,atoms){const fromAtom=atoms[bond.from];const toAtom=atoms[bond.to];const startAndEndPos=maybeShrinkLines(fromAtom,toAtom);return {type:"line:"+bond.bondType,startPos:startAndEndPos[0],endPos:startAndEndPos[1]}}function idxString(idx){return idx.join(":")}function convertTree(atoms,bonds,tree){if(tree===null){return [atoms,bonds]}if(tree.type==="atom"){const treeIdx=idxString(tree.idx);atoms[treeIdx]={idx:treeIdx,symbol:tree.symbol,connections:[]};if(tree.bonds){tree.bonds.forEach(function(b){const toIdx=idxString(b.to.idx);atoms[treeIdx].connections.push(toIdx);bonds.push({from:treeIdx,to:toIdx,bondType:b.bondType});convertTree(atoms,bonds,b.to);atoms[toIdx].connections.push(treeIdx);});}}return [atoms,bonds]}function atomLayoutHelper(outputs,atomProcessingQueue,atoms,bonds,rotationAngle){if(atomProcessingQueue.length===0){return outputs}const queuedAtomIdx=atomProcessingQueue.shift();const atom=atoms[queuedAtomIdx];atom.connections.forEach(function(c){if(!atoms[c].pos){atomProcessingQueue.push(c);}});return atomLayoutHelper(outputs.concat(atomLayout(atom,atoms,bonds,rotationAngle)),atomProcessingQueue,atoms,bonds,rotationAngle)}function bondLayoutHelper(outputs,atoms,bonds){if(bonds.length===0){return outputs}return bondLayoutHelper(outputs.concat(bondLayout(bonds[0],atoms)),atoms,bonds.slice(1))}function layout$1(tree,rotationAngle){const converted=convertTree({},[],tree);const atoms=converted[0];const bonds=converted[1];const outputs=atomLayoutHelper([],["1,0"],atoms,bonds,rotationAngle);return bondLayoutHelper(outputs,atoms,bonds)}var MoleculeLayout = {layout:layout$1};
2094
2094
 
@@ -2098,7 +2098,7 @@ const{layout}=MoleculeLayout;const parse=SmilesParser.parse;const ParseError=Smi
2098
2098
 
2099
2099
  const getPromptJSON$6=widgetData=>{const{userInput}=widgetData;return {type:"number-line",options:{range:widgetData.range,snapDivisions:widgetData.snapDivisions},userInput:{numLinePosition:userInput.numLinePosition,numDivisions:userInput.numDivisions,rel:userInput.rel}}};
2100
2100
 
2101
- const MovablePoint=Graphie.MovablePoint;const Line=Graphie.Line;const{assert: assert$1}=InteractiveUtil;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";const horizontalPadding=30;const reverseRel={eq:"eq",ge:"le",gt:"lt",le:"ge",lt:"gt"};const toggleStrictRel={eq:"eq",ge:"gt",gt:"ge",le:"lt",lt:"le"};function formatImproper(n,d){if(d===1){return ""+n}return `\\dfrac{${n}}{${d}}`}function formatMixed(n,d){if(n<0){return "-"+formatMixed(-n,d)}const w=Math.floor(n/d);if(w===0){return formatImproper(n,d)}if(n-w*d===0){return ""+w}return w+formatImproper(n-w*d,d)}function formatNonReduced(n,d,base){const factor=Math.floor(base/d);return formatImproper(n*factor,base)}const _label=(graphie,labelStyle,pos,value,base)=>{value=value||pos;if(labelStyle==="decimal"||labelStyle==="decimal ticks"){return graphie.label([pos,-0.53],Math.round(value*100)/100,"center")}if(labelStyle==="improper"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatImproper(frac[0],frac[1]),"below")}if(labelStyle==="mixed"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatMixed(frac[0],frac[1]),"below")}if(labelStyle==="non-reduced"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatNonReduced(frac[0],frac[1],base),"below")}};const TickMarks=Graphie.createSimpleClass((graphie,props)=>{if(!___default.default.isFinite(props.tickStep)||props.tickStep<=0){return []}const results=[];const{range,labelRange,labelStyle,labelTicks,tickStep,numDivisions}=props;const leftLabel=labelRange[0]==null?range[0]:labelRange[0];const rightLabel=labelRange[1]==null?range[1]:labelRange[1];let base;if(labelStyle==="non-reduced"){const fractions=[leftLabel,rightLabel];for(let i=0;i<=numDivisions;i++){const x=range[0]+i*tickStep;fractions.push(x);}const getDenom=x=>kmath.number.toFraction(x)[1];const denoms=___default.default.map(fractions,getDenom);base=___default.default.reduce(denoms,(x,y)=>kmath.KhanMath.getLCM(x,y));}else {base=undefined;}const highlightedLineStyle={stroke:KhanColors.BLUE,strokeWidth:3.5};const highlightedTextStyle={color:KhanColors.BLUE};const initialTicks=[...Array(Math.round(numDivisions)).keys()].map(index=>range[0]+index*tickStep);const byNumericAscending=(a,b)=>a-b;const allTicks=[...new Set([...initialTicks,leftLabel,rightLabel,...range])].sort(byNumericAscending);allTicks.forEach(tick=>{const tickIsHighlighted=tick===leftLabel||tick===rightLabel;const lineStyle=tickIsHighlighted?highlightedLineStyle:null;const textStyle=tickIsHighlighted?highlightedTextStyle:null;graphie.style(lineStyle,()=>{results.push(graphie.line([tick,-0.2],[tick,.2]));});if(labelTicks||tickIsHighlighted||labelStyle==="decimal ticks"){graphie.style(textStyle,()=>{results.push(_label(graphie,labelStyle,tick,tick,base));});}});return results});class NumberLine extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"number-line",widgetId:this.props.widgetId}});}getIsTickCtrl(){return this.props.isTickCtrl??NumberLine.defaultProps.isTickCtrl}getSnapDivisions(){return this.props.snapDivisions??NumberLine.defaultProps.snapDivisions}focus(){if(this.getIsTickCtrl()){this.refs["tick-ctrl"].focus();return true}return false}getDOMNodeForPath(inputPath){if(inputPath?.length===1){return ReactDOM__namespace.default.findDOMNode(this.refs[inputPath[0]])}return null}_getInequalityEndpoint(props){const isGreater=___default.default(["ge","gt"]).contains(this.props.userInput.rel);const widthInPixels=400;const range=props.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const end=isGreater?[right,0]:[left,0];return end}_renderInequality(props){if(props.isInequality){const end=this._getInequalityEndpoint(props);const style={arrows:"->",stroke:this.props.apiOptions.isMobile?KhanColors.GREEN:KhanColors.BLUE,strokeWidth:3.5};return jsxRuntimeExports.jsx(Line,{start:[props.userInput.numLinePosition,0],end:end,style:style})}return null}getPromptJSON(){return getPromptJSON$6(this.props)}getSerializedState(){const props=this.props;return {alignment:props.alignment,static:props.static,range:props.range,labelRange:props.labelRange,labelStyle:props.labelStyle,labelTicks:props.labelTicks,divisionRange:props.divisionRange,snapDivisions:props.snapDivisions,isInequality:props.isInequality,showTooltips:props.showTooltips,isTickCtrl:props.isTickCtrl,numDivisions:props.userInput.numDivisions,numLinePosition:props.userInput.numLinePosition,rel:"ge"}}render(){const{strings}=this.context;const divisionRange=this.props.divisionRange;const divRangeString=divisionRange[0]+EN_DASH+divisionRange[1];const invalidNumDivisions=this.props.userInput?.numDivisions<divisionRange[0]||this.props.userInput?.numDivisions>divisionRange[1];const inequalityControls=jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:strings.switchDirection,onClick:this.handleReverse}),jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:["le","ge"].includes(this.props.userInput?.rel)?strings.circleOpen:strings.circleFilled,onClick:this.handleToggleStrict})]});let tickCtrl;if(this.getIsTickCtrl()){let Input;if(this.props.apiOptions.customKeypad){Input=SimpleKeypadInput;}else {Input=NumberInput;}tickCtrl=jsxRuntimeExports.jsxs("label",{children:[strings.numDivisions," ",jsxRuntimeExports.jsx(Input,{ref:"tick-ctrl",value:this.state.numDivisionsEmpty?null:this.props.userInput?.numDivisions||divisionRange[0],checkValidity:val=>val>=divisionRange[0]&&val<=divisionRange[1],onChange:this.onNumDivisionsChange,onFocus:this._handleTickCtrlFocus,onBlur:this._handleTickCtrlBlur,useArrowKeys:true,keypadElement:this.props.keypadElement})]});}return jsxRuntimeExports.jsxs("div",{className:"perseus-widget "+"perseus-widget-interactive-number-line",children:[tickCtrl,!this.isValid()?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:"Invalid number line configuration."}):this.getIsTickCtrl()&&invalidNumDivisions?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:strings.divisions({divRangeString:divRangeString})}):this._renderGraphie(),!this.props.static&&this.props.isInequality&&inequalityControls]})}constructor(...args){super(...args),this.state={numDivisionsEmpty:false},this.isValid=()=>{const range=this.props.range;let initialX=this.props.userInput?.numLinePosition;const divisionRange=this.props.divisionRange;initialX=initialX==null?range[0]:initialX;return range[0]<range[1]&&kmath.number.sign(initialX-range[0])>=0&&kmath.number.sign(initialX-range[1])<=0&&divisionRange[0]<divisionRange[1]&&0<this.props.userInput?.numDivisions&&0<this.getSnapDivisions()},this.onNumDivisionsChange=(numDivisions,cb)=>{const width=this.props.range[1]-this.props.range[0];numDivisions=Math.round(numDivisions);numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){const nextProps={...this.props,tickStep:width/numDivisions};const newNumLinePosition=this.snapNumLinePosition(nextProps,this.props.userInput.numLinePosition);this.setState({numDivisionsEmpty:false},()=>{this.props.handleUserInput({...this.props.userInput,numDivisions:numDivisions,numLinePosition:newNumLinePosition},cb);});}else {this.setState({numDivisionsEmpty:true},cb);}},this._handleTickCtrlFocus=()=>{this.props.onFocus(["tick-ctrl"]);},this._handleTickCtrlBlur=()=>{this.props.onBlur(["tick-ctrl"]);},this.focusInputPath=path=>{if(path.length===1){this.refs[path[0]].focus();}},this.blurInputPath=path=>{if(path.length===1){this.refs[path[0]].blur();}},this.getInputPaths=()=>{if(this.getIsTickCtrl()){return [["tick-ctrl"]]}return []},this._renderGraphie=()=>{const range=this.props.range;const width=range[1]-range[0];const options={range:this.props.range,isTickCtrl:this.getIsTickCtrl()};const props={...this.props,tickStep:width/this.props.userInput.numDivisions};return jsxRuntimeExports.jsxs(Graphie,{ref:"graphie",box:[this.props.apiOptions.isMobile?288:460,80],options:options,onMouseDown:coord=>{this.refs.graphie.movables.numberLinePoint.grab(coord);},setup:this._setupGraphie,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,children:[jsxRuntimeExports.jsx(TickMarks,{range:props.range,labelTicks:props.labelTicks,labelStyle:props.labelStyle,labelRange:props.labelRange,tickStep:props.tickStep,numDivisions:props.userInput.numDivisions,isMobile:props.apiOptions.isMobile}),this._renderInequality(props),this._renderNumberLinePoint(props)]},this.props.labelStyle)},this.snapNumLinePosition=(props,numLinePosition)=>{const left=props.range[0];const right=props.range[1];const snapX=props.tickStep/this.getSnapDivisions();let x=bound(numLinePosition,left,right);x=left+kmath.number.roundTo(x-left,snapX);assert$1(___default.default.isFinite(x));return x},this.movePosition=targetPosition=>{this.props.handleUserInput({...this.props.userInput,numLinePosition:targetPosition});this.props.trackInteraction();},this._renderNumberLinePoint=props=>{const isOpen=___default.default(["lt","gt"]).contains(props.userInput.rel);let fill;if(isOpen){fill=KhanColors._BACKGROUND;}else if(props.static){fill=KhanColors.BLUE;}else {fill=KhanColors.GREEN;}const normalStyle={fill:fill,stroke:props.static?KhanColors.BLUE:KhanColors.GREEN,"stroke-width":isOpen?3:1};const highlightStyle={fill:isOpen?KhanColors._BACKGROUND:KhanColors.GREEN,"stroke-width":isOpen?3:1};const mobileDotStyle=props.isInequality?{stroke:KhanColors.GREEN,"fill-opacity":isOpen?0:1}:{};return jsxRuntimeExports.jsx(MovablePoint,{ref:"numberLinePoint",pointSize:6,coord:[props.userInput.numLinePosition,0],constraints:[(coord,prevCoord)=>{return [coord[0],prevCoord[1]]},(coord,prevCoord)=>{const x=this.snapNumLinePosition(props,coord[0]);return [x,coord[1]]}],normalStyle:normalStyle,highlightStyle:highlightStyle,onMove:coord=>{this.movePosition(coord[0]);},isMobile:this.props.apiOptions.isMobile,mobileStyleOverride:mobileDotStyle,showTooltips:this.props.showTooltips,xOnlyTooltip:true})},this.handleReverse=()=>{const newRel=reverseRel[this.props.userInput.rel];this.props.handleUserInput({...this.props.userInput,rel:newRel});},this.handleToggleStrict=()=>{const newRel=toggleStrictRel[this.props.userInput.rel];this.props.handleUserInput({...this.props.userInput,rel:newRel});},this._setupGraphie=(graphie,options)=>{if(!this.isValid()){return}const widthInPixels=this.props.apiOptions.isMobile?288-horizontalPadding*2:400;const range=options.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const hasFractionalLabels=this.props.labelStyle==="improper"||this.props.labelStyle==="mixed"||this.props.labelStyle==="non-reduced";const bottom=hasFractionalLabels?-1.5:-1;const top=1;graphie.init({range:[[left,right],[bottom,top]],scale:[1/scale,40],isMobile:this.props.apiOptions.isMobile});const center=(range[0]+range[1])/2;graphie.line([center,0],[right,0],{arrows:"->"});graphie.line([center,0],[left,0],{arrows:"->"});};}}NumberLine.contextType=PerseusI18nContext;NumberLine.defaultProps={range:[0,10],labelStyle:"decimal",labelRange:[null,null],divisionRange:[1,12],labelTicks:true,isTickCtrl:false,isInequality:false,snapDivisions:2,showTooltips:false,apiOptions:ApiOptions.defaults};function getUserInputFromSerializedState$4(serializedState){return {numDivisions:serializedState.numDivisions,numLinePosition:serializedState.numLinePosition,rel:"eq"}}function getStartNumDivisions(options){const width=options.range[1]-options.range[0];let numDivisions;if(options.numDivisions!=null){numDivisions=options.numDivisions;}else if(options.tickStep!=null){numDivisions=width/options.tickStep;}else {numDivisions=undefined;}return numDivisions}function getCorrectUserInput$1(options){const numLinePosition=options.correctX!=null?options.correctX:options.range[0];return {numDivisions:getStartNumDivisions(options),numLinePosition,rel:options.isInequality&&options.correctRel||"eq"}}function getStartUserInput$4(options){const numLinePosition=options.initialX!=null?options.initialX:options.range[0];return {numDivisions:getStartNumDivisions(options),numLinePosition,rel:options.isInequality?"ge":"eq"}}const WrappedNumberLine=withDependencies(NumberLine);var NumberLine$1 = {name:"number-line",displayName:"Number line",widget:WrappedNumberLine,getCorrectUserInput: getCorrectUserInput$1,getStartUserInput: getStartUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$4};
2101
+ const MovablePoint=Graphie.MovablePoint;const Line=Graphie.Line;const{assert: assert$1}=InteractiveUtil;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";const horizontalPadding=30;const reverseRel={eq:"eq",ge:"le",gt:"lt",le:"ge",lt:"gt"};const toggleStrictRel={eq:"eq",ge:"gt",gt:"ge",le:"lt",lt:"le"};function formatImproper(n,d){if(d===1){return ""+n}return `\\dfrac{${n}}{${d}}`}function formatMixed(n,d){if(n<0){return "-"+formatMixed(-n,d)}const w=Math.floor(n/d);if(w===0){return formatImproper(n,d)}if(n-w*d===0){return ""+w}return w+formatImproper(n-w*d,d)}function formatNonReduced(n,d,base){const factor=Math.floor(base/d);return formatImproper(n*factor,base)}const _label=(graphie,labelStyle,pos,value,base)=>{value=value||pos;if(labelStyle==="decimal"||labelStyle==="decimal ticks"){return graphie.label([pos,-0.53],Math.round(value*100)/100,"center")}if(labelStyle==="improper"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatImproper(frac[0],frac[1]),"below")}if(labelStyle==="mixed"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatMixed(frac[0],frac[1]),"below")}if(labelStyle==="non-reduced"){const frac=kmath.KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatNonReduced(frac[0],frac[1],base),"below")}};const TickMarks=Graphie.createSimpleClass((graphie,props)=>{if(!___default.default.isFinite(props.tickStep)||props.tickStep<=0){return []}const results=[];const{range,labelRange,labelStyle,labelTicks,tickStep,numDivisions}=props;const leftLabel=labelRange[0]==null?range[0]:labelRange[0];const rightLabel=labelRange[1]==null?range[1]:labelRange[1];let base;if(labelStyle==="non-reduced"){const fractions=[leftLabel,rightLabel];for(let i=0;i<=numDivisions;i++){const x=range[0]+i*tickStep;fractions.push(x);}const getDenom=x=>kmath.number.toFraction(x)[1];const denoms=___default.default.map(fractions,getDenom);base=___default.default.reduce(denoms,(x,y)=>kmath.KhanMath.getLCM(x,y));}else {base=undefined;}const highlightedLineStyle={stroke:KhanColors.BLUE,strokeWidth:3.5};const highlightedTextStyle={color:KhanColors.BLUE};const initialTicks=[...Array(Math.round(numDivisions)).keys()].map(index=>range[0]+index*tickStep);const byNumericAscending=(a,b)=>a-b;const allTicks=[...new Set([...initialTicks,leftLabel,rightLabel,...range])].sort(byNumericAscending);allTicks.forEach(tick=>{const tickIsHighlighted=tick===leftLabel||tick===rightLabel;const lineStyle=tickIsHighlighted?highlightedLineStyle:null;const textStyle=tickIsHighlighted?highlightedTextStyle:null;graphie.style(lineStyle,()=>{results.push(graphie.line([tick,-0.2],[tick,.2]));});if(labelTicks||tickIsHighlighted||labelStyle==="decimal ticks"){graphie.style(textStyle,()=>{results.push(_label(graphie,labelStyle,tick,tick,base));});}});return results});class NumberLine extends React__namespace.Component{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"number-line",widgetId:this.props.widgetId}});}getIsTickCtrl(){return this.props.isTickCtrl??NumberLine.defaultProps.isTickCtrl}getSnapDivisions(){return this.props.snapDivisions??NumberLine.defaultProps.snapDivisions}focus(){if(this.getIsTickCtrl()){this.refs["tick-ctrl"].focus();return true}return false}getDOMNodeForPath(inputPath){if(inputPath?.length===1){return ReactDOM__namespace.default.findDOMNode(this.refs[inputPath[0]])}return null}_getInequalityEndpoint(props){const isGreater=___default.default(["ge","gt"]).contains(this.props.userInput.rel);const widthInPixels=400;const range=props.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const end=isGreater?[right,0]:[left,0];return end}_renderInequality(props){if(props.isInequality){const end=this._getInequalityEndpoint(props);const style={arrows:"->",stroke:this.props.apiOptions.isMobile?KhanColors.GREEN:KhanColors.BLUE,strokeWidth:3.5};return jsxRuntimeExports.jsx(Line,{start:[props.userInput.numLinePosition,0],end:end,style:style})}return null}getPromptJSON(){return getPromptJSON$6(this.props)}getSerializedState(){const props=this.props;return {alignment:props.alignment,static:props.static,range:props.range,labelRange:props.labelRange,labelStyle:props.labelStyle,labelTicks:props.labelTicks,divisionRange:props.divisionRange,snapDivisions:props.snapDivisions,isInequality:props.isInequality,showTooltips:props.showTooltips,isTickCtrl:props.isTickCtrl,numDivisions:props.userInput.numDivisions,numLinePosition:props.userInput.numLinePosition,rel:"ge"}}render(){const{strings}=this.context;const divisionRange=this.props.divisionRange;const divRangeString=divisionRange[0]+EN_DASH+divisionRange[1];const invalidNumDivisions=this.props.userInput?.numDivisions<divisionRange[0]||this.props.userInput?.numDivisions>divisionRange[1];const inequalityControls=jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:strings.switchDirection,onClick:this.handleReverse}),jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:["le","ge"].includes(this.props.userInput?.rel)?strings.circleOpen:strings.circleFilled,onClick:this.handleToggleStrict})]});let tickCtrl;if(this.getIsTickCtrl()){let Input;if(this.props.apiOptions.customKeypad){Input=SimpleKeypadInput;}else {Input=NumberInput;}tickCtrl=jsxRuntimeExports.jsxs("label",{children:[strings.numDivisions," ",jsxRuntimeExports.jsx(Input,{ref:"tick-ctrl",value:this.state.numDivisionsEmpty?null:this.props.userInput?.numDivisions||divisionRange[0],checkValidity:val=>val>=divisionRange[0]&&val<=divisionRange[1],onChange:this.onNumDivisionsChange,onFocus:this._handleTickCtrlFocus,onBlur:this._handleTickCtrlBlur,useArrowKeys:true,keypadElement:this.props.keypadElement})]});}return jsxRuntimeExports.jsxs("div",{className:"perseus-widget "+"perseus-widget-interactive-number-line",children:[tickCtrl,!this.isValid()?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:"Invalid number line configuration."}):this.getIsTickCtrl()&&invalidNumDivisions?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:strings.divisions({divRangeString:divRangeString})}):this._renderGraphie(),!this.props.static&&this.props.isInequality&&inequalityControls]})}constructor(...args){super(...args),this.state={numDivisionsEmpty:false},this.isValid=()=>{const range=this.props.range;let initialX=this.props.userInput?.numLinePosition;const divisionRange=this.props.divisionRange;initialX=initialX==null?range[0]:initialX;return range[0]<range[1]&&kmath.number.sign(initialX-range[0])>=0&&kmath.number.sign(initialX-range[1])<=0&&divisionRange[0]<divisionRange[1]&&0<this.props.userInput?.numDivisions&&0<this.getSnapDivisions()},this.onNumDivisionsChange=(numDivisions,cb)=>{const width=this.props.range[1]-this.props.range[0];numDivisions=Math.round(numDivisions);numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){const nextProps={...this.props,tickStep:width/numDivisions};const newNumLinePosition=this.snapNumLinePosition(nextProps,this.props.userInput.numLinePosition);this.setState({numDivisionsEmpty:false},()=>{this.props.handleUserInput({...this.props.userInput,numDivisions:numDivisions,numLinePosition:newNumLinePosition},cb);});}else {this.setState({numDivisionsEmpty:true},cb);}},this._handleTickCtrlFocus=()=>{this.props.onFocus(["tick-ctrl"]);},this._handleTickCtrlBlur=()=>{this.props.onBlur(["tick-ctrl"]);},this.focusInputPath=path=>{if(path.length===1){this.refs[path[0]].focus();}},this.blurInputPath=path=>{if(path.length===1){this.refs[path[0]].blur();}},this.getInputPaths=()=>{if(this.getIsTickCtrl()){return [["tick-ctrl"]]}return []},this._renderGraphie=()=>{const range=this.props.range;const width=range[1]-range[0];const options={range:this.props.range,isTickCtrl:this.getIsTickCtrl()};const props={...this.props,tickStep:width/this.props.userInput.numDivisions};return jsxRuntimeExports.jsxs(Graphie,{ref:"graphie",box:[this.props.apiOptions.isMobile?288:460,80],options:options,onMouseDown:coord=>{this.refs.graphie.movables.numberLinePoint.grab(coord);},setup:this._setupGraphie,isMobile:this.props.apiOptions.isMobile,children:[jsxRuntimeExports.jsx(TickMarks,{range:props.range,labelTicks:props.labelTicks,labelStyle:props.labelStyle,labelRange:props.labelRange,tickStep:props.tickStep,numDivisions:props.userInput.numDivisions,isMobile:props.apiOptions.isMobile}),this._renderInequality(props),this._renderNumberLinePoint(props)]},this.props.labelStyle)},this.snapNumLinePosition=(props,numLinePosition)=>{const left=props.range[0];const right=props.range[1];const snapX=props.tickStep/this.getSnapDivisions();let x=bound(numLinePosition,left,right);x=left+kmath.number.roundTo(x-left,snapX);assert$1(___default.default.isFinite(x));return x},this.movePosition=targetPosition=>{this.props.handleUserInput({...this.props.userInput,numLinePosition:targetPosition});this.props.trackInteraction();},this._renderNumberLinePoint=props=>{const isOpen=___default.default(["lt","gt"]).contains(props.userInput.rel);let fill;if(isOpen){fill=KhanColors._BACKGROUND;}else if(props.static){fill=KhanColors.BLUE;}else {fill=KhanColors.GREEN;}const normalStyle={fill:fill,stroke:props.static?KhanColors.BLUE:KhanColors.GREEN,"stroke-width":isOpen?3:1};const highlightStyle={fill:isOpen?KhanColors._BACKGROUND:KhanColors.GREEN,"stroke-width":isOpen?3:1};const mobileDotStyle=props.isInequality?{stroke:KhanColors.GREEN,"fill-opacity":isOpen?0:1}:{};return jsxRuntimeExports.jsx(MovablePoint,{ref:"numberLinePoint",pointSize:6,coord:[props.userInput.numLinePosition,0],constraints:[(coord,prevCoord)=>{return [coord[0],prevCoord[1]]},(coord,prevCoord)=>{const x=this.snapNumLinePosition(props,coord[0]);return [x,coord[1]]}],normalStyle:normalStyle,highlightStyle:highlightStyle,onMove:coord=>{this.movePosition(coord[0]);},isMobile:this.props.apiOptions.isMobile,mobileStyleOverride:mobileDotStyle,showTooltips:this.props.showTooltips,xOnlyTooltip:true})},this.handleReverse=()=>{const newRel=reverseRel[this.props.userInput.rel];this.props.handleUserInput({...this.props.userInput,rel:newRel});},this.handleToggleStrict=()=>{const newRel=toggleStrictRel[this.props.userInput.rel];this.props.handleUserInput({...this.props.userInput,rel:newRel});},this._setupGraphie=(graphie,options)=>{if(!this.isValid()){return}const widthInPixels=this.props.apiOptions.isMobile?288-horizontalPadding*2:400;const range=options.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const hasFractionalLabels=this.props.labelStyle==="improper"||this.props.labelStyle==="mixed"||this.props.labelStyle==="non-reduced";const bottom=hasFractionalLabels?-1.5:-1;const top=1;graphie.init({range:[[left,right],[bottom,top]],scale:[1/scale,40],isMobile:this.props.apiOptions.isMobile});const center=(range[0]+range[1])/2;graphie.line([center,0],[right,0],{arrows:"->"});graphie.line([center,0],[left,0],{arrows:"->"});};}}NumberLine.contextType=PerseusI18nContext;NumberLine.defaultProps={range:[0,10],labelStyle:"decimal",labelRange:[null,null],divisionRange:[1,12],labelTicks:true,isTickCtrl:false,isInequality:false,snapDivisions:2,showTooltips:false,apiOptions:ApiOptions.defaults};function getUserInputFromSerializedState$4(serializedState){return {numDivisions:serializedState.numDivisions,numLinePosition:serializedState.numLinePosition,rel:"eq"}}function getStartNumDivisions(options){const width=options.range[1]-options.range[0];let numDivisions;if(options.numDivisions!=null){numDivisions=options.numDivisions;}else if(options.tickStep!=null){numDivisions=width/options.tickStep;}else {numDivisions=undefined;}return numDivisions}function getCorrectUserInput$1(options){const numLinePosition=options.correctX!=null?options.correctX:options.range[0];return {numDivisions:getStartNumDivisions(options),numLinePosition,rel:options.isInequality&&options.correctRel||"eq"}}function getStartUserInput$4(options){const numLinePosition=options.initialX!=null?options.initialX:options.range[0];return {numDivisions:getStartNumDivisions(options),numLinePosition,rel:options.isInequality?"ge":"eq"}}const WrappedNumberLine=withDependencies(NumberLine);var NumberLine$1 = {name:"number-line",displayName:"Number line",widget:WrappedNumberLine,getCorrectUserInput: getCorrectUserInput$1,getStartUserInput: getStartUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$4};
2102
2102
 
2103
2103
  const getPromptJSON$5=widgetData=>{return {type:"orderer",options:{options:widgetData.options.map(option=>option.content)},userInput:{values:widgetData.userInput.current}}};
2104
2104
 
@@ -2106,15 +2106,15 @@ class PlaceholderCard extends React__namespace.Component{render(){return jsxRunt
2106
2106
 
2107
2107
  const getPromptJSON$4=()=>{return getUnsupportedPromptJSON("phet-simulation")};
2108
2108
 
2109
- 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);}}getLocale(){switch(this.context.locale){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 this.context.locale}}getPromptJSON(){return getPromptJSON$4()}async updateSimState(urlString){const url=perseusCore.makeSafeUrl(urlString,this.getLocale(),"https://phet.colorado.edu");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.getLocale().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(...args){super(...args),this.iframeRef=React__namespace.createRef(),this.isWidget=true,this.state={url:null,banner:null,isFullScreen:false},this.displayLoadFailure=()=>{this.setState({url:null,banner:{message:this.context.strings.simulationLoadFail,kind:"critical"}});},this.toggleFullScreen=()=>{this.setState(prevState=>({isFullScreen:!prevState.isFullScreen}));};}}PhetSimulation.contextType=PerseusI18nContext;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};
2109
+ 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);}}getLocale(){switch(this.context.locale){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 this.context.locale}}getPromptJSON(){return getPromptJSON$4()}async updateSimState(urlString){const url=perseusCore.makeSafeUrl(urlString,this.getLocale(),"https://phet.colorado.edu");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.getLocale().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$6.appFullScreenWidgetContainer}:styles$6.widgetContainer;const iframeContainerStyle=isMobileAppFullscreen?styles$6.appFullScreenIframeContainer:styles$6.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$6.closeButtonContainer,children:jsxRuntimeExports.jsx(IconButton__default.default,{icon:xIcon__default.default,onClick:this.toggleFullScreen,kind:"tertiary",actionType:"neutral","aria-label":"Exit fullscreen",style:styles$6.closeButton})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:iframeContainerStyle,children:jsxRuntimeExports.jsx("iframe",{ref:this.iframeRef,title:this.props.description,sandbox:sandboxProperties,className:aphrodite.css(styles$6.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(...args){super(...args),this.iframeRef=React__namespace.createRef(),this.isWidget=true,this.state={url:null,banner:null,isFullScreen:false},this.displayLoadFailure=()=>{this.setState({url:null,banner:{message:this.context.strings.simulationLoadFail,kind:"critical"}});},this.toggleFullScreen=()=>{this.setState(prevState=>({isFullScreen:!prevState.isFullScreen}));};}}PhetSimulation.contextType=PerseusI18nContext;const styles$6=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};
2110
2110
 
2111
2111
  const getPromptJSON$3=()=>{return getUnsupportedPromptJSON("plotter")};
2112
2112
 
2113
- const plotterDefaults=perseusCore.CoreWidgetRegistry.getDefaultWidgetOptions("plotter");class Plotter extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.setupGraphie(this.props.userInput);this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"plotter",widgetSubType:"null",widgetId:this.props.widgetId}});}UNSAFE_componentWillReceiveProps(nextProps){const props=["type","labels","categories","scaleY","maxY","snapsPerLine","picUrl","labelInterval","static"];this.shouldSetupGraphie=___default.default.any(props,prop=>!___default.default.isEqual(this.props[prop],nextProps[prop]),this);if(!___default.default.isEqual(this.props.starting,nextProps.starting)&&!___default.default.isEqual(this.props.userInput,nextProps.starting)){this.shouldSetupGraphie=true;this.props.handleUserInput(nextProps.starting);}}componentDidUpdate(prevProps,prevState){this.shouldSetupGraphie=this.shouldSetupGraphie||!___default.default.isEqual(this.state.categoryHeights,prevState.categoryHeights);if(this.shouldSetupGraphie){this.setupGraphie(prevProps.userInput);}}componentWillUnmount(){this._isMounted=false;}setupGraphie(prevValues){const self=this;self.shouldSetupGraphie=false;$__default.default(this.graphieDiv.current).empty();const graphie=GraphUtils.createGraphie(this.graphieDiv.current);self.graphie=graphie;self.graphie.pics=[];self.graphie.dotTicks=[];const isBar=self.props.type==="bar";const isLine=self.props.type==="line";const isPic=self.props.type==="pic";const isHistogram=self.props.type==="histogram";const isDotplot=self.props.type==="dotplot";const isTiledPlot=isPic||isDotplot;const config={};const c=config;const isMobile=this.props.apiOptions.isMobile;c.graph={lines:[],bars:[],points:[],dividers:[]};c.scaleY=self.props.scaleY;c.dimX=self.props.categories.length;const plotDimensions=isMobile?[288,336]:self.props.plotDimensions;if(isLine){c.dimX+=isMobile?-0.2:1;}else if(isHistogram){c.barPad=0;c.barWidth=1;}else if(isBar){c.barPad=isMobile?.08:.15;c.barWidth=1-2*c.barPad;c.dimX+=(isMobile?-2:2)*c.barPad;}else if(isTiledPlot){c.picBoxHeight=self.props.picBoxHeight;c.picBoxWidthPx=plotDimensions[0]/self.props.categories.length;const picPadAllWidth=plotDimensions[0]-c.dimX*c.picBoxWidthPx;c.picPad=picPadAllWidth/(2*c.dimX+2);const picFullWidth=c.picBoxWidthPx+2*c.picPad;c.picPad=c.picPad/picFullWidth;c.picBoxWidth=c.picBoxWidthPx/picFullWidth;c.dimX+=2*c.picPad;}if(isDotplot){c.picBoxHeight=this.DOT_PLOT_POINT_SIZE()*2+this.DOT_PLOT_POINT_PADDING();}c.dimY=Math.ceil(self.props.maxY/c.scaleY)*c.scaleY;let padX=25;if((isBar||isLine)&&isMobile){padX=self.props.labels[1].length!==0?17:11;}if(isDotplot){padX/=2;}if(isMobile&&isTiledPlot&&self.props.labels[1].length===0){padX=0;}let padTop=25;let padBottom=25*3;if(isMobile&&(isBar||isTiledPlot)){const maxCategoryHeight=Math.max(0,...Object.values(self.state.categoryHeights));if(maxCategoryHeight){let offsetY=25;if(isTiledPlot){offsetY+=10;}padBottom=offsetY+maxCategoryHeight;}}if(isMobile){c.scale=[(plotDimensions[0]-padX*4)/c.dimX,(plotDimensions[1]-(padTop+padBottom))/c.dimY];}else {c.scale=___default.default.map([c.dimX,c.dimY],function(dim,i){return plotDimensions[i]/dim});}if(isTiledPlot){c.scale[1]=c.picBoxHeight/c.scaleY;}padX/=c.scale[0];padTop/=c.scale[1];padBottom/=c.scale[1];graphie.init({range:[[-3*padX,c.dimX+padX],[-padBottom,c.dimY+padTop]],scale:c.scale,isMobile:this.props.apiOptions.isMobile});graphie.addMouseLayer({allowScratchpad:true,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable});if(!isTiledPlot){const initialY=isMobile?c.scaleY:0;for(let y=initialY;y<=c.dimY;y+=c.scaleY){graphie.label([0,y],kmath.KhanMath.roundToApprox(y,2),"left",true);graphie.style({stroke:isMobile?"#e9ebec":"#000",strokeWidth:1,opacity:isMobile?1:.3},function(){graphie.line([0,y],[c.dimX,y]);});}}if((isBar||isLine)&&isMobile&&!this.props.static){self.graphie.dragPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.dragHandles,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}self.setupCategories(config);if(isTiledPlot&&isMobile){self.graphie.dotPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.tapAddPoints,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}if(isTiledPlot){self.drawPicHeights(self.props.userInput,prevValues);}graphie.style({stroke:"#000",strokeWidth:2,opacity:1},function(){if(isTiledPlot){if(isDotplot){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?0:.5,0],[c.dimX-(isMobile?0:.5),0]));}else {graphie.line([0,0],[c.dimX,0]);if(self.props.labels[1].length!==0||!isMobile){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}}else {graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?-padX*3:0,0],[c.dimX+(isMobile?padX:0),0]));if(!((isBar||isLine)&&isMobile)){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}});const xAxisLabel=graphie.label([c.dimX/2,isMobile?-padBottom:-35/c.scale[1]],self.props.labels[0],isMobile?"above":"below",false).css("font-weight","bold");if(isMobile){xAxisLabel.css("color",KhanColors.GRAY_F);}const yAxisLabel=graphie.label([(isMobile?-35:-60)/c.scale[0],c.dimY/2],self.props.labels[1],"center",false).css("font-weight","bold").addClass("rotate");if(isMobile){yAxisLabel.css("color",KhanColors.GRAY_F);}if(this.props.apiOptions.isMobile){this.horizHairline=new WrappedLine(this.graphie,[0,0],[0,0],{normalStyle:{strokeWidth:1}});this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.hairlineRange=[[0,c.dimX],[0,c.dimY]];}}_testInsertUserInput(userInput){this.props.handleUserInput(userInput);}drawPicHeights(values,prevValues){const self=this;const graphie=self.graphie;const pics=graphie.pics;const isMobile=this.props.apiOptions.isMobile;if(isMobile){const shouldDisplay=values.every(v=>v===0);graphie.dotPrompt[0].style.display=shouldDisplay?"inline":"none";}___default.default.each(pics,function(ps,i){___default.default.each(ps,function(pic,j){const y=(j+1)*self.props.scaleY;const show=y<=values[i];if(self.props.type==="dotplot"){const wasShown=y<=prevValues[i];const wasJustShown=show&&!wasShown;if(wasJustShown){pic.animate({"stroke-width":8},75,()=>pic.animate({"stroke-width":2},75));}}$__default.default(pic[0]).css({display:show?"inline":"none"});graphie.dotTicks[i][j][0].style.display=show||!isMobile?"none":"inline";});});}getPromptJSON(){return getPromptJSON$3()}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,values:this.props.userInput}}render(){const paddingForBottomLabel=75;const style={marginBottom:this.props.labels[0]?paddingForBottomLabel:0};return jsxRuntimeExports.jsx("div",{className:"perseus-widget-plotter graphie",ref:this.graphieDiv,style:style})}constructor(...args){super(...args),this._isMounted=false,this.graphieDiv=React__namespace.createRef(),this.state={categoryHeights:{}},this.DOT_PLOT_POINT_SIZE=()=>{return this.props.apiOptions.isMobile?6:4},this.DOT_PLOT_POINT_PADDING=()=>{return 8},this.DOT_TICK_POINT_SIZE=()=>{return 2},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.hairlineRange[0][0],point[1]],[this.hairlineRange[0][1],point[1]]);this.horizHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();}},this.labelCategory=(x,category)=>{const isMobile=this.props.apiOptions.isMobile;const graphie=this.graphie;category=category+"";let isTeX=false;const mathyCategory=category.match(/^\$(.*)\$$/);if(mathyCategory){category=mathyCategory[1];isTeX=true;}const translateX=5;const rotationDeg=45;const rotationRad=rotationDeg*(Math.PI/180);const labelRotation=`translateX(-50%) translateX(${translateX}px) `+`translateY(-50%) rotate(-${rotationDeg}deg)`;const shouldRotate=isMobile&&!mathyCategory;return new Promise(resolve=>{graphie.style({color:isMobile?KhanColors.GRAY_G:"inherit",transform:shouldRotate?labelRotation:"none",transformOrigin:"100%"},()=>{const $span=graphie.label([x,isMobile?-0.5:0],category,"below",isTeX);const height=14+(shouldRotate?Math.round($span.height()*Math.cos(rotationRad)+($span.width()+translateX)*Math.sin(rotationRad)):$span.height());resolve({category,height});});})},this.setupCategories=config=>{const self=this;const c=config;const graphie=self.graphie;const isMobile=this.props.apiOptions.isMobile;const categoryHeightPromises=[];if(self.props.type==="histogram"){___default.default.times(self.props.categories.length-1,function(i){self.setupBar({index:i,startHeight:self.props.userInput[i],config:config,isHistogram:true});});___default.default.each(self.props.categories,function(category,i){const x=.5+i*c.barWidth;categoryHeightPromises.push(self.labelCategory(x,category));const tickHeight=6/c.scale[1];graphie.style({stroke:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,-tickHeight],[x,0]);});});}else {___default.default.each(self.props.categories,function(category,i){const startHeight=self.props.userInput[i];let x;if(self.props.type==="bar"){x=self.setupBar({index:i,startHeight:startHeight,config:config,isHistogram:false});}else if(self.props.type==="line"){x=self.setupLine(i,startHeight,config);}else if(self.props.type==="pic"){x=self.setupPic(i,config);}else if(self.props.type==="dotplot"){x=self.setupDotplot(i,config);}let tickStart=0;let tickEnd=-6/c.scale[1];if(self.props.type==="dotplot"&&!isMobile){tickStart=-tickEnd;}if(self.props.type==="dotplot"){if(i%self.props.labelInterval===0||i===self.props.categories.length-1){categoryHeightPromises.push(self.labelCategory(x,category));tickStart*=1.5;tickEnd*=1.5;}}else {categoryHeightPromises.push(self.labelCategory(x,category));}graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,tickStart],[x,tickEnd]);});});}Promise.all(categoryHeightPromises).then(measurements=>{if(self._isMounted){const categoryHeights={};measurements.forEach(({category,height})=>categoryHeights[category]=height);self.setState({categoryHeights});}});},this._clampValue=(v,min,max)=>{return Math.max(Math.min(v,max),min)},this._maybeShowDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="inline";}},this._maybeHideDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="none";}},this.setupBar=args=>{const isMobile=this.props.apiOptions.isMobile;const i=args.index;const startHeight=args.startHeight;const config=args.config;const isHistogram=args.isHistogram;const self=this;const graphie=self.graphie;const barHalfWidth=config.barWidth/2;let x;if(isHistogram){x=.5+i*config.barWidth+barHalfWidth;}else {x=(isMobile?barHalfWidth:.5+config.barPad)+i;}const scaleBar=function(i,height){const center=graphie.scalePoint(0);config.graph.bars[i].scale(1,Math.max(isMobile?.2:.01,height/config.scaleY),center[0],center[1]);if(isHistogram){const leftDivider=config.graph.dividers[i-1];const rightDivider=config.graph.dividers[i];if(leftDivider){const divHeight=Math.min(self.props.userInput[i-1],height);leftDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}if(rightDivider){const divHeight=Math.min(self.props.userInput[i+1],height);rightDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}}};graphie.style({stroke:"none",fill:isMobile?KhanColors.BLUE_C:KhanColors.LIGHT_BLUE,opacity:1},function(){config.graph.bars[i]=graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY],[x+barHalfWidth,config.scaleY],[x+barHalfWidth,0],[x-barHalfWidth,0]]);});if(isHistogram){if(i>0){graphie.style({stroke:"#000",strokeWidth:1,opacity:.3},function(){config.graph.dividers.push(graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY]]));});}}if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;config.graph.lines[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMoveStart:function(){config.graph.bars[i].attr({fill:KhanColors.INTERACTIVE});},onMove:function(){const y=config.graph.lines[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();scaleBar(i,y);},onMoveEnd:function(){config.graph.bars[i].attr({fill:KhanColors.BLUE_C});}});config.graph.lines[i].state.visibleShape.wrapper.style.zIndex="1";self._maybeShowDragPrompt();}else {config.graph.lines[i]=graphie.addMovableLineSegment({coordA:[x-barHalfWidth,startHeight],coordZ:[x+barHalfWidth,startHeight],snapY:config.scaleY/self.props.snapsPerLine,constraints:{constrainX:true},normalStyle:{stroke:KhanColors.INTERACTIVE,"stroke-width":this.props.static?0:4}});config.graph.lines[i].onMove=function(dx,dy){let y=this.coordA[1];if(y<0||y>config.dimY){y=Math.min(Math.max(y,0),config.dimY);this.coordA[1]=this.coordZ[1]=y;this.transform();}const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);scaleBar(i,y);};}scaleBar(i,startHeight);return x},this.setupLine=(i,startHeight,config)=>{const isMobile=this.props.apiOptions.isMobile;const self=this;const c=config;const graphie=self.graphie;const x=i+(isMobile?.4:1);if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;c.graph.points[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMove:function(){const y=c.graph.points[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();}});self._maybeShowDragPrompt();if(i>0){c.graph.lines[i]=Interactive2.addMovableLine(graphie,{points:[c.graph.points[i-1],c.graph.points[i]],constraints:Interactive2.MovablePoint.constraints.fixed(),normalStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2},highlightStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2}});}}else {c.graph.points[i]=graphie.addMovablePoint({coord:[x,startHeight],constraints:{constrainX:true},normalStyle:{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE},snapY:c.scaleY/self.props.snapsPerLine});c.graph.points[i].onMove=function(x,y){y=Math.min(Math.max(y,0),c.dimY);const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);return [x,y]};if(i>0){c.graph.lines[i]=graphie.addMovableLineSegment({pointA:c.graph.points[i-1],pointZ:c.graph.points[i],constraints:{fixed:true},normalStyle:{stroke:"#9ab8ed","stroke-width":2}});}}return x},this.setupDotplot=(i,config)=>{const graphie=this.graphie;const isMobile=this.props.apiOptions.isMobile;return this.setupTiledPlot(i,isMobile?.5:1,config,(x,y)=>{return graphie.ellipse([x,y],[this.DOT_PLOT_POINT_SIZE()/graphie.scale[0],this.DOT_PLOT_POINT_SIZE()/graphie.scale[1]],{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE})})},this.setupPic=(i,config)=>{const graphie=this.graphie;return this.setupTiledPlot(i,0,config,(x,y)=>{const scaledCenter=graphie.scalePoint([x,y]);const size=this.props.picSize;return graphie.raphael.image(this.props.picUrl,scaledCenter[0]-size/2,scaledCenter[1]-size/2,size,size)})},this.setupTiledPlot=(i,bottomMargin,config,createImage)=>{const self=this;const c=config;const graphie=self.graphie;const pics=graphie.pics;const dotTicks=graphie.dotTicks;const x=i+.5+c.picPad;graphie.mouselayer.canvas.style.touchAction="none";pics[i]=[];dotTicks[i]=[];const n=Math.round(c.dimY/c.scaleY)+1;___default.default(n).times(function(j){j-=1;const midY=(j+.5)*c.scaleY;const leftX=x-c.picBoxWidth/2;const topY=midY+.5*c.scaleY;const coord=graphie.scalePoint([leftX,topY+bottomMargin]);const mouseRect=graphie.mouselayer.rect(coord[0],coord[1],c.picBoxWidthPx,c.picBoxHeight);$__default.default(mouseRect[0]).css({fill:"#000",opacity:0,cursor:"pointer"}).on("vmousedown",function(e){e.preventDefault();self.whichPicClicked=i;self.setPicHeight(i,topY);$__default.default(document).on("vmouseup.plotTile",function(e){$__default.default(document).unbind(".plotTile");});$__default.default(document).on("vmousemove.plotTile",function(e){e.preventDefault();const yCoord=graphie.getMouseCoord(e)[1];const adjustedCoord=Math.floor(yCoord-bottomMargin);const newJ=Math.max(-1,Math.floor(adjustedCoord/c.scaleY));const newMidY=(newJ+.5)*c.scaleY;const newTopY=Math.min(newMidY+.5*c.scaleY,c.dimY);self.setPicHeight(self.whichPicClicked,newTopY);});});if(j<0){return}pics[i][j]=createImage(x,midY+bottomMargin);dotTicks[i][j]=graphie.ellipse([x,midY+bottomMargin],[self.DOT_TICK_POINT_SIZE()/graphie.scale[0],self.DOT_TICK_POINT_SIZE()/graphie.scale[1]],{fill:"#dee1e3",stroke:"#dee1e3"});});return x},this.setPicHeight=(i,y)=>{const values=[...this.props.userInput];values[i]=y;this.drawPicHeights(values,this.props.userInput);this.changeAndTrack(values);},this.changeAndTrack=userInput=>{this.props.handleUserInput(userInput);this.props.trackInteraction();};}}Plotter.contextType=PerseusI18nContext;Plotter.defaultProps=plotterDefaults;function getStartUserInput$2(options){return options.starting}function getCorrectUserInput(options){return options.correct}function getUserInputFromSerializedState$2(serializedState){return serializedState.values}const WrappedPlotter=withDependencies(Plotter);var Plotter$1 = {name:"plotter",displayName:"Plotter",hidden:true,widget:WrappedPlotter,getCorrectUserInput,getStartUserInput: getStartUserInput$2,getUserInputFromSerializedState: getUserInputFromSerializedState$2};
2113
+ const plotterDefaults=perseusCore.CoreWidgetRegistry.getDefaultWidgetOptions("plotter");class Plotter extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.setupGraphie(this.props.userInput);this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetType:"plotter",widgetSubType:"null",widgetId:this.props.widgetId}});}UNSAFE_componentWillReceiveProps(nextProps){const props=["type","labels","categories","scaleY","maxY","snapsPerLine","picUrl","labelInterval","static"];this.shouldSetupGraphie=___default.default.any(props,prop=>!___default.default.isEqual(this.props[prop],nextProps[prop]),this);if(!___default.default.isEqual(this.props.starting,nextProps.starting)&&!___default.default.isEqual(this.props.userInput,nextProps.starting)){this.shouldSetupGraphie=true;this.props.handleUserInput(nextProps.starting);}}componentDidUpdate(prevProps,prevState){this.shouldSetupGraphie=this.shouldSetupGraphie||!___default.default.isEqual(this.state.categoryHeights,prevState.categoryHeights);if(this.shouldSetupGraphie){this.setupGraphie(prevProps.userInput);}}componentWillUnmount(){this._isMounted=false;}setupGraphie(prevValues){const self=this;self.shouldSetupGraphie=false;$__default.default(this.graphieDiv.current).empty();const graphie=GraphUtils.createGraphie(this.graphieDiv.current);self.graphie=graphie;self.graphie.pics=[];self.graphie.dotTicks=[];const isBar=self.props.type==="bar";const isLine=self.props.type==="line";const isPic=self.props.type==="pic";const isHistogram=self.props.type==="histogram";const isDotplot=self.props.type==="dotplot";const isTiledPlot=isPic||isDotplot;const config={};const c=config;const isMobile=this.props.apiOptions.isMobile;c.graph={lines:[],bars:[],points:[],dividers:[]};c.scaleY=self.props.scaleY;c.dimX=self.props.categories.length;const plotDimensions=isMobile?[288,336]:self.props.plotDimensions;if(isLine){c.dimX+=isMobile?-0.2:1;}else if(isHistogram){c.barPad=0;c.barWidth=1;}else if(isBar){c.barPad=isMobile?.08:.15;c.barWidth=1-2*c.barPad;c.dimX+=(isMobile?-2:2)*c.barPad;}else if(isTiledPlot){c.picBoxHeight=self.props.picBoxHeight;c.picBoxWidthPx=plotDimensions[0]/self.props.categories.length;const picPadAllWidth=plotDimensions[0]-c.dimX*c.picBoxWidthPx;c.picPad=picPadAllWidth/(2*c.dimX+2);const picFullWidth=c.picBoxWidthPx+2*c.picPad;c.picPad=c.picPad/picFullWidth;c.picBoxWidth=c.picBoxWidthPx/picFullWidth;c.dimX+=2*c.picPad;}if(isDotplot){c.picBoxHeight=this.DOT_PLOT_POINT_SIZE()*2+this.DOT_PLOT_POINT_PADDING();}c.dimY=Math.ceil(self.props.maxY/c.scaleY)*c.scaleY;let padX=25;if((isBar||isLine)&&isMobile){padX=self.props.labels[1].length!==0?17:11;}if(isDotplot){padX/=2;}if(isMobile&&isTiledPlot&&self.props.labels[1].length===0){padX=0;}let padTop=25;let padBottom=25*3;if(isMobile&&(isBar||isTiledPlot)){const maxCategoryHeight=Math.max(0,...Object.values(self.state.categoryHeights));if(maxCategoryHeight){let offsetY=25;if(isTiledPlot){offsetY+=10;}padBottom=offsetY+maxCategoryHeight;}}if(isMobile){c.scale=[(plotDimensions[0]-padX*4)/c.dimX,(plotDimensions[1]-(padTop+padBottom))/c.dimY];}else {c.scale=___default.default.map([c.dimX,c.dimY],function(dim,i){return plotDimensions[i]/dim});}if(isTiledPlot){c.scale[1]=c.picBoxHeight/c.scaleY;}padX/=c.scale[0];padTop/=c.scale[1];padBottom/=c.scale[1];graphie.init({range:[[-3*padX,c.dimX+padX],[-padBottom,c.dimY+padTop]],scale:c.scale,isMobile:this.props.apiOptions.isMobile});graphie.addMouseLayer({allowScratchpad:true});if(!isTiledPlot){const initialY=isMobile?c.scaleY:0;for(let y=initialY;y<=c.dimY;y+=c.scaleY){graphie.label([0,y],kmath.KhanMath.roundToApprox(y,2),"left",true);graphie.style({stroke:isMobile?"#e9ebec":"#000",strokeWidth:1,opacity:isMobile?1:.3},function(){graphie.line([0,y],[c.dimX,y]);});}}if((isBar||isLine)&&isMobile&&!this.props.static){self.graphie.dragPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.dragHandles,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}self.setupCategories(config);if(isTiledPlot&&isMobile){self.graphie.dotPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.tapAddPoints,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}if(isTiledPlot){self.drawPicHeights(self.props.userInput,prevValues);}graphie.style({stroke:"#000",strokeWidth:2,opacity:1},function(){if(isTiledPlot){if(isDotplot){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?0:.5,0],[c.dimX-(isMobile?0:.5),0]));}else {graphie.line([0,0],[c.dimX,0]);if(self.props.labels[1].length!==0||!isMobile){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}}else {graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?-padX*3:0,0],[c.dimX+(isMobile?padX:0),0]));if(!((isBar||isLine)&&isMobile)){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}});const xAxisLabel=graphie.label([c.dimX/2,isMobile?-padBottom:-35/c.scale[1]],self.props.labels[0],isMobile?"above":"below",false).css("font-weight","bold");if(isMobile){xAxisLabel.css("color",KhanColors.GRAY_F);}const yAxisLabel=graphie.label([(isMobile?-35:-60)/c.scale[0],c.dimY/2],self.props.labels[1],"center",false).css("font-weight","bold").addClass("rotate");if(isMobile){yAxisLabel.css("color",KhanColors.GRAY_F);}if(this.props.apiOptions.isMobile){this.horizHairline=new WrappedLine(this.graphie,[0,0],[0,0],{normalStyle:{strokeWidth:1}});this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.hairlineRange=[[0,c.dimX],[0,c.dimY]];}}_testInsertUserInput(userInput){this.props.handleUserInput(userInput);}drawPicHeights(values,prevValues){const self=this;const graphie=self.graphie;const pics=graphie.pics;const isMobile=this.props.apiOptions.isMobile;if(isMobile){const shouldDisplay=values.every(v=>v===0);graphie.dotPrompt[0].style.display=shouldDisplay?"inline":"none";}___default.default.each(pics,function(ps,i){___default.default.each(ps,function(pic,j){const y=(j+1)*self.props.scaleY;const show=y<=values[i];if(self.props.type==="dotplot"){const wasShown=y<=prevValues[i];const wasJustShown=show&&!wasShown;if(wasJustShown){pic.animate({"stroke-width":8},75,()=>pic.animate({"stroke-width":2},75));}}$__default.default(pic[0]).css({display:show?"inline":"none"});graphie.dotTicks[i][j][0].style.display=show||!isMobile?"none":"inline";});});}getPromptJSON(){return getPromptJSON$3()}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,values:this.props.userInput}}render(){const paddingForBottomLabel=75;const style={marginBottom:this.props.labels[0]?paddingForBottomLabel:0};return jsxRuntimeExports.jsx("div",{className:"perseus-widget-plotter graphie",ref:this.graphieDiv,style:style})}constructor(...args){super(...args),this._isMounted=false,this.graphieDiv=React__namespace.createRef(),this.state={categoryHeights:{}},this.DOT_PLOT_POINT_SIZE=()=>{return this.props.apiOptions.isMobile?6:4},this.DOT_PLOT_POINT_PADDING=()=>{return 8},this.DOT_TICK_POINT_SIZE=()=>{return 2},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.hairlineRange[0][0],point[1]],[this.hairlineRange[0][1],point[1]]);this.horizHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();}},this.labelCategory=(x,category)=>{const isMobile=this.props.apiOptions.isMobile;const graphie=this.graphie;category=category+"";let isTeX=false;const mathyCategory=category.match(/^\$(.*)\$$/);if(mathyCategory){category=mathyCategory[1];isTeX=true;}const translateX=5;const rotationDeg=45;const rotationRad=rotationDeg*(Math.PI/180);const labelRotation=`translateX(-50%) translateX(${translateX}px) `+`translateY(-50%) rotate(-${rotationDeg}deg)`;const shouldRotate=isMobile&&!mathyCategory;return new Promise(resolve=>{graphie.style({color:isMobile?KhanColors.GRAY_G:"inherit",transform:shouldRotate?labelRotation:"none",transformOrigin:"100%"},()=>{const $span=graphie.label([x,isMobile?-0.5:0],category,"below",isTeX);const height=14+(shouldRotate?Math.round($span.height()*Math.cos(rotationRad)+($span.width()+translateX)*Math.sin(rotationRad)):$span.height());resolve({category,height});});})},this.setupCategories=config=>{const self=this;const c=config;const graphie=self.graphie;const isMobile=this.props.apiOptions.isMobile;const categoryHeightPromises=[];if(self.props.type==="histogram"){___default.default.times(self.props.categories.length-1,function(i){self.setupBar({index:i,startHeight:self.props.userInput[i],config:config,isHistogram:true});});___default.default.each(self.props.categories,function(category,i){const x=.5+i*c.barWidth;categoryHeightPromises.push(self.labelCategory(x,category));const tickHeight=6/c.scale[1];graphie.style({stroke:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,-tickHeight],[x,0]);});});}else {___default.default.each(self.props.categories,function(category,i){const startHeight=self.props.userInput[i];let x;if(self.props.type==="bar"){x=self.setupBar({index:i,startHeight:startHeight,config:config,isHistogram:false});}else if(self.props.type==="line"){x=self.setupLine(i,startHeight,config);}else if(self.props.type==="pic"){x=self.setupPic(i,config);}else if(self.props.type==="dotplot"){x=self.setupDotplot(i,config);}let tickStart=0;let tickEnd=-6/c.scale[1];if(self.props.type==="dotplot"&&!isMobile){tickStart=-tickEnd;}if(self.props.type==="dotplot"){if(i%self.props.labelInterval===0||i===self.props.categories.length-1){categoryHeightPromises.push(self.labelCategory(x,category));tickStart*=1.5;tickEnd*=1.5;}}else {categoryHeightPromises.push(self.labelCategory(x,category));}graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,tickStart],[x,tickEnd]);});});}Promise.all(categoryHeightPromises).then(measurements=>{if(self._isMounted){const categoryHeights={};measurements.forEach(({category,height})=>categoryHeights[category]=height);self.setState({categoryHeights});}});},this._clampValue=(v,min,max)=>{return Math.max(Math.min(v,max),min)},this._maybeShowDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="inline";}},this._maybeHideDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="none";}},this.setupBar=args=>{const isMobile=this.props.apiOptions.isMobile;const i=args.index;const startHeight=args.startHeight;const config=args.config;const isHistogram=args.isHistogram;const self=this;const graphie=self.graphie;const barHalfWidth=config.barWidth/2;let x;if(isHistogram){x=.5+i*config.barWidth+barHalfWidth;}else {x=(isMobile?barHalfWidth:.5+config.barPad)+i;}const scaleBar=function(i,height){const center=graphie.scalePoint(0);config.graph.bars[i].scale(1,Math.max(isMobile?.2:.01,height/config.scaleY),center[0],center[1]);if(isHistogram){const leftDivider=config.graph.dividers[i-1];const rightDivider=config.graph.dividers[i];if(leftDivider){const divHeight=Math.min(self.props.userInput[i-1],height);leftDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}if(rightDivider){const divHeight=Math.min(self.props.userInput[i+1],height);rightDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}}};graphie.style({stroke:"none",fill:isMobile?KhanColors.BLUE_C:KhanColors.LIGHT_BLUE,opacity:1},function(){config.graph.bars[i]=graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY],[x+barHalfWidth,config.scaleY],[x+barHalfWidth,0],[x-barHalfWidth,0]]);});if(isHistogram){if(i>0){graphie.style({stroke:"#000",strokeWidth:1,opacity:.3},function(){config.graph.dividers.push(graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY]]));});}}if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;config.graph.lines[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMoveStart:function(){config.graph.bars[i].attr({fill:KhanColors.INTERACTIVE});},onMove:function(){const y=config.graph.lines[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();scaleBar(i,y);},onMoveEnd:function(){config.graph.bars[i].attr({fill:KhanColors.BLUE_C});}});config.graph.lines[i].state.visibleShape.wrapper.style.zIndex="1";self._maybeShowDragPrompt();}else {config.graph.lines[i]=graphie.addMovableLineSegment({coordA:[x-barHalfWidth,startHeight],coordZ:[x+barHalfWidth,startHeight],snapY:config.scaleY/self.props.snapsPerLine,constraints:{constrainX:true},normalStyle:{stroke:KhanColors.INTERACTIVE,"stroke-width":this.props.static?0:4}});config.graph.lines[i].onMove=function(dx,dy){let y=this.coordA[1];if(y<0||y>config.dimY){y=Math.min(Math.max(y,0),config.dimY);this.coordA[1]=this.coordZ[1]=y;this.transform();}const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);scaleBar(i,y);};}scaleBar(i,startHeight);return x},this.setupLine=(i,startHeight,config)=>{const isMobile=this.props.apiOptions.isMobile;const self=this;const c=config;const graphie=self.graphie;const x=i+(isMobile?.4:1);if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;c.graph.points[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMove:function(){const y=c.graph.points[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();}});self._maybeShowDragPrompt();if(i>0){c.graph.lines[i]=Interactive2.addMovableLine(graphie,{points:[c.graph.points[i-1],c.graph.points[i]],constraints:Interactive2.MovablePoint.constraints.fixed(),normalStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2},highlightStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2}});}}else {c.graph.points[i]=graphie.addMovablePoint({coord:[x,startHeight],constraints:{constrainX:true},normalStyle:{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE},snapY:c.scaleY/self.props.snapsPerLine});c.graph.points[i].onMove=function(x,y){y=Math.min(Math.max(y,0),c.dimY);const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);return [x,y]};if(i>0){c.graph.lines[i]=graphie.addMovableLineSegment({pointA:c.graph.points[i-1],pointZ:c.graph.points[i],constraints:{fixed:true},normalStyle:{stroke:"#9ab8ed","stroke-width":2}});}}return x},this.setupDotplot=(i,config)=>{const graphie=this.graphie;const isMobile=this.props.apiOptions.isMobile;return this.setupTiledPlot(i,isMobile?.5:1,config,(x,y)=>{return graphie.ellipse([x,y],[this.DOT_PLOT_POINT_SIZE()/graphie.scale[0],this.DOT_PLOT_POINT_SIZE()/graphie.scale[1]],{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE})})},this.setupPic=(i,config)=>{const graphie=this.graphie;return this.setupTiledPlot(i,0,config,(x,y)=>{const scaledCenter=graphie.scalePoint([x,y]);const size=this.props.picSize;return graphie.raphael.image(this.props.picUrl,scaledCenter[0]-size/2,scaledCenter[1]-size/2,size,size)})},this.setupTiledPlot=(i,bottomMargin,config,createImage)=>{const self=this;const c=config;const graphie=self.graphie;const pics=graphie.pics;const dotTicks=graphie.dotTicks;const x=i+.5+c.picPad;graphie.mouselayer.canvas.style.touchAction="none";pics[i]=[];dotTicks[i]=[];const n=Math.round(c.dimY/c.scaleY)+1;___default.default(n).times(function(j){j-=1;const midY=(j+.5)*c.scaleY;const leftX=x-c.picBoxWidth/2;const topY=midY+.5*c.scaleY;const coord=graphie.scalePoint([leftX,topY+bottomMargin]);const mouseRect=graphie.mouselayer.rect(coord[0],coord[1],c.picBoxWidthPx,c.picBoxHeight);$__default.default(mouseRect[0]).css({fill:"#000",opacity:0,cursor:"pointer"}).on("vmousedown",function(e){e.preventDefault();self.whichPicClicked=i;self.setPicHeight(i,topY);$__default.default(document).on("vmouseup.plotTile",function(e){$__default.default(document).unbind(".plotTile");});$__default.default(document).on("vmousemove.plotTile",function(e){e.preventDefault();const yCoord=graphie.getMouseCoord(e)[1];const adjustedCoord=Math.floor(yCoord-bottomMargin);const newJ=Math.max(-1,Math.floor(adjustedCoord/c.scaleY));const newMidY=(newJ+.5)*c.scaleY;const newTopY=Math.min(newMidY+.5*c.scaleY,c.dimY);self.setPicHeight(self.whichPicClicked,newTopY);});});if(j<0){return}pics[i][j]=createImage(x,midY+bottomMargin);dotTicks[i][j]=graphie.ellipse([x,midY+bottomMargin],[self.DOT_TICK_POINT_SIZE()/graphie.scale[0],self.DOT_TICK_POINT_SIZE()/graphie.scale[1]],{fill:"#dee1e3",stroke:"#dee1e3"});});return x},this.setPicHeight=(i,y)=>{const values=[...this.props.userInput];values[i]=y;this.drawPicHeights(values,this.props.userInput);this.changeAndTrack(values);},this.changeAndTrack=userInput=>{this.props.handleUserInput(userInput);this.props.trackInteraction();};}}Plotter.contextType=PerseusI18nContext;Plotter.defaultProps=plotterDefaults;function getStartUserInput$2(options){return options.starting}function getCorrectUserInput(options){return options.correct}function getUserInputFromSerializedState$2(serializedState){return serializedState.values}const WrappedPlotter=withDependencies(Plotter);var Plotter$1 = {name:"plotter",displayName:"Plotter",hidden:true,widget:WrappedPlotter,getCorrectUserInput,getStartUserInput: getStartUserInput$2,getUserInputFromSerializedState: getUserInputFromSerializedState$2};
2114
2114
 
2115
2115
  const getPromptJSON$2=()=>{return getUnsupportedPromptJSON("python-program")};
2116
2116
 
2117
- 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",kaLocale:this.context?.locale});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",{title:this.context.strings.pythonProgram,sandbox:sandboxOptions,src:url,style:iframeStyle,allowFullScreen:true})})}}PythonProgram.contextType=PerseusI18nContext;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};
2117
+ 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",kaLocale:this.context?.locale});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$5.container,children:jsxRuntimeExports.jsx("iframe",{title:this.context.strings.pythonProgram,sandbox:sandboxOptions,src:url,style:iframeStyle,allowFullScreen:true})})}}PythonProgram.contextType=PerseusI18nContext;PythonProgram.defaultProps={height:400};const styles$5=aphrodite.StyleSheet.create({container:{margin:"auto",width:"100%"}});const WrappedPythonProgram=withDependencies(PythonProgram);var PythonProgram$1 = {name:"python-program",displayName:"Python Program",widget:WrappedPythonProgram};
2118
2118
 
2119
2119
  const getPromptJSON$1=userInput=>{return {type:"sorter",userInput:{values:userInput.options,changed:userInput.changed}}};
2120
2120
 
@@ -2124,15 +2124,17 @@ const{assert}=InteractiveUtil;function getInputPath(row,column){return [""+row,"
2124
2124
 
2125
2125
  const getPromptJSON=()=>{return getUnsupportedPromptJSON("video")};
2126
2126
 
2127
- 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"}});
2127
+ 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$4.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$4=aphrodite.StyleSheet.create({transcriptLink:{flexDirection:"row",width:"100%",justifyContent:"center"}});
2128
2128
 
2129
- 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{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"video",widgetId:this.props.widgetId}});}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",kaLocale:this.context.locale});return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{children:[jsxRuntimeExports.jsx(FixedToResponsive,{width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,children:jsxRuntimeExports.jsx("iframe",{title:this.context.strings.videoWrapper,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};
2129
+ var styles$3 = {"perseusVideoWidget":"perseus_gxXDcWBe","perseusVideoFixedToResponsive":"perseus_5hjlD7xq"};
2130
+
2131
+ 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{componentDidMount(){this.props.dependencies.analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:"null",widgetType:"video",widgetId:this.props.widgetId}});}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",kaLocale:this.context.locale});return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{children:[jsxRuntimeExports.jsx(FixedToResponsive,{className:styles$3.perseusVideoFixedToResponsive,width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,children:jsxRuntimeExports.jsx("iframe",{title:this.context.strings.videoWrapper,className:styles$3.perseusVideoWidget,sandbox:"allow-same-origin allow-scripts",width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,src:url,allowFullScreen:true,allow:"autoplay"})},location),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};
2130
2132
 
2131
2133
  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,PhetSimulation$1,Plotter$1,PythonProgram$1,Sorter$1,Table$1,Video$1];
2132
2134
 
2133
2135
  const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
2134
2136
 
2135
- const libName="@khanacademy/perseus";const libVersion="77.11.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2137
+ const libName="@khanacademy/perseus";const libVersion="78.0.1";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2136
2138
 
2137
2139
  const apiVersion={major:12,minor:0};
2138
2140