@khanacademy/perseus 78.0.0 → 78.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var React = require('react');
6
6
  var keypadContext = require('@khanacademy/keypad-context');
7
7
  var mathInput = require('@khanacademy/math-input');
8
- var perseusCore = require('@khanacademy/perseus-core');
9
8
  var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
10
9
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
11
10
  var aphrodite = require('aphrodite');
@@ -17,6 +16,7 @@ var $ = require('jquery');
17
16
  var _ = require('underscore');
18
17
  var uuid = require('uuid');
19
18
  var PropTypes = require('prop-types');
19
+ var perseusCore = require('@khanacademy/perseus-core');
20
20
  var PerseusLinter = require('@khanacademy/perseus-linter');
21
21
  var perseusScore = require('@khanacademy/perseus-score');
22
22
  var Tooltip = require('@khanacademy/wonder-blocks-tooltip');
@@ -45,14 +45,14 @@ var caretDown = require('@phosphor-icons/core/regular/caret-down.svg');
45
45
  var caretUp = require('@phosphor-icons/core/regular/caret-up.svg');
46
46
  var wonderBlocksLabeledField = require('@khanacademy/wonder-blocks-labeled-field');
47
47
  var warningCircleIcon = require('@phosphor-icons/core/regular/warning-circle.svg');
48
- var infoIconBold = require('@phosphor-icons/core/bold/info-bold.svg');
48
+ var invariant = require('tiny-invariant');
49
+ var mafs = require('mafs');
50
+ var react = require('@use-gesture/react');
49
51
  var questionIcon = require('@phosphor-icons/core/regular/question.svg');
52
+ var KAS = require('@khanacademy/kas');
53
+ var infoIconBold = require('@phosphor-icons/core/bold/info-bold.svg');
50
54
  var pauseIcon = require('@phosphor-icons/core/fill/pause-fill.svg');
51
55
  var playIcon = require('@phosphor-icons/core/fill/play-fill.svg');
52
- var KAS = require('@khanacademy/kas');
53
- var mafs = require('mafs');
54
- var react = require('@use-gesture/react');
55
- var invariant = require('tiny-invariant');
56
56
  var Switch = require('@khanacademy/wonder-blocks-switch');
57
57
  var Pill = require('@khanacademy/wonder-blocks-pill');
58
58
  var reactPopper = require('react-popper');
@@ -103,12 +103,12 @@ var Button__default = /*#__PURE__*/_interopDefaultCompat(Button);
103
103
  var caretDown__default = /*#__PURE__*/_interopDefaultCompat(caretDown);
104
104
  var caretUp__default = /*#__PURE__*/_interopDefaultCompat(caretUp);
105
105
  var warningCircleIcon__default = /*#__PURE__*/_interopDefaultCompat(warningCircleIcon);
106
- var infoIconBold__default = /*#__PURE__*/_interopDefaultCompat(infoIconBold);
106
+ var invariant__default = /*#__PURE__*/_interopDefaultCompat(invariant);
107
107
  var questionIcon__default = /*#__PURE__*/_interopDefaultCompat(questionIcon);
108
+ var KAS__namespace = /*#__PURE__*/_interopNamespaceCompat(KAS);
109
+ var infoIconBold__default = /*#__PURE__*/_interopDefaultCompat(infoIconBold);
108
110
  var pauseIcon__default = /*#__PURE__*/_interopDefaultCompat(pauseIcon);
109
111
  var playIcon__default = /*#__PURE__*/_interopDefaultCompat(playIcon);
110
- var KAS__namespace = /*#__PURE__*/_interopNamespaceCompat(KAS);
111
- var invariant__default = /*#__PURE__*/_interopDefaultCompat(invariant);
112
112
  var Switch__default = /*#__PURE__*/_interopDefaultCompat(Switch);
113
113
  var Pill__default = /*#__PURE__*/_interopDefaultCompat(Pill);
114
114
  var cornersOutIcon__default = /*#__PURE__*/_interopDefaultCompat(cornersOutIcon);
@@ -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
 
@@ -1483,7 +1483,7 @@ const ApiOptions={propTypes:PropTypes__default.default.shape({isArticle:PropType
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,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,...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(()=>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
 
@@ -1663,9 +1663,9 @@ const Status={PENDING:"pending",LOADING:"loading",LOADED:"loaded",FAILED:"failed
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
 
@@ -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
 
@@ -1701,7 +1701,7 @@ const{interactiveSizes}=constants;const smMax=articleMaxWidthTableInPx;const mdM
1701
1701
 
1702
1702
  function getWidgetTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];return widget?.type??null}function getWidgetSubType(widgetType,widgetOptions){switch(widgetType){case "interactive-graph":const graphOptions=widgetOptions;return graphOptions.graph?.type??null;case "radio":const radioOptions=widgetOptions;return radioOptions.multipleSelect?"multiple-select":"single-select";default:return null}}function getWidgetSubTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];if(!widget){return null}return getWidgetSubType(widget.type,widget.options)}function contentHasWidgetType(type,content,widgetMap){return perseusCore.getWidgetIdsFromContentByType(type,content,widgetMap).length>0}function getWidgetFromWidgetMap(widgetId,widgetMap){return widgetMap[widgetId]??null}function getWidgetsFromWidgetMap(widgetIds,widgetMap){const widgets={};widgetIds.forEach(widgetId=>{const widget=getWidgetFromWidgetMap(widgetId,widgetMap);if(widget){widgets[widgetId]=widget;}});return widgets}
1703
1703
 
1704
- const DEFAULT_TRACKING="";const DEFAULT_LINTABLE=false;const widgets=new perseusCore.Registry("Perseus widget registry");const editors=new perseusCore.Registry("Perseus widget editor registry");const registerWidget=(type,widget)=>{widgets.set(type,widget);};const registerWidgets=widgetArr=>{widgetArr.forEach(widget=>{registerWidget(widget.name,widget);});};const replaceWidget=(type,replacementType)=>{const substituteWidget=widgets.get(replacementType);if(!substituteWidget){const errorMsg=`Failed to replace ${type} with ${replacementType}`;throw new perseusCore.PerseusError(errorMsg,perseusCore.Errors.Internal)}registerWidget(type,substituteWidget);};const replaceDeprecatedWidgets=()=>{replaceWidget("transformer","deprecated-standin");replaceWidget("lights-puzzle","deprecated-standin");replaceWidget("reaction-diagram","deprecated-standin");replaceWidget("sequence","deprecated-standin");replaceWidget("simulator","deprecated-standin");replaceWidget("unit-input","deprecated-standin");replaceWidget("passage","deprecated-standin");replaceWidget("passage-ref","deprecated-standin");replaceWidget("passage-ref-target","deprecated-standin");};const registerEditors=editorsToRegister=>{editorsToRegister.forEach(editor=>{if(!editor.widgetName){throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`,perseusCore.Errors.Internal)}editors.set(editor.widgetName,editor);});};const replaceEditor=(type,replacementType)=>{const substituteEditor=editors.get(replacementType);if(!substituteEditor&&Log){const errorMsg=`Failed to replace editor ${type} with ${replacementType}`;Log.error(errorMsg,perseusCore.Errors.Internal);return}editors.set(type,substituteEditor);};const replaceDeprecatedEditors=()=>{replaceEditor("transformer","deprecated-standin");replaceEditor("lights-puzzle","deprecated-standin");replaceEditor("reaction-diagram","deprecated-standin");replaceEditor("sequence","deprecated-standin");replaceEditor("simulator","deprecated-standin");replaceEditor("unit-input","deprecated-standin");replaceEditor("passage","deprecated-standin");replaceEditor("passage-ref","deprecated-standin");replaceEditor("passage-ref-target","deprecated-standin");};const getWidget=type=>{const widget=widgets.get(type);if(widget==null){return null}if(widget.getWidget){return widget.getWidget()}return widget.widget};const getWidgetExport=type=>{return widgets.get(type)??null};const getEditor=type=>{return editors.get(type)??null};const getVersion=type=>{const widget=widgets.get(type);if(widget!=null){return widget.version||{major:0,minor:0}}return};const getVersionVector=()=>{const version={};widgets.keys().forEach(type=>{version[type]=getVersion(type);});return version};const getPublicWidgets=()=>{return widgets.entries().reduce((acc,[key,value])=>{if(process.env.STORYBOOK||!value.hidden){acc[key]=value;}return acc},{})};const getAllWidgetTypes=()=>{return widgets.keys()};const supportsStaticMode=type=>{const widgetInfo=widgets.get(type);return widgetInfo&&widgetInfo.getCorrectUserInput!=null};const supportsUngraded=type=>{const widgetInfo=widgets.get(type);return widgetInfo?.supportsUngraded===true};const getTracking=type=>{const widgetExport=widgets.get(type);return widgetExport&&widgetExport.tracking||DEFAULT_TRACKING};const isLintable=type=>{const widgetExports=widgets.get(type);return widgetExports&&widgetExports.isLintable||DEFAULT_LINTABLE};
1704
+ const DEFAULT_TRACKING="";const DEFAULT_LINTABLE=false;const widgets=new perseusCore.Registry("Perseus widget registry");const editors=new perseusCore.Registry("Perseus widget editor registry");const registerWidget=(type,widget)=>{widgets.set(type,widget);};const registerWidgets=widgetArr=>{widgetArr.forEach(widget=>{registerWidget(widget.name,widget);});};const replaceWidget=(type,replacementType)=>{const substituteWidget=widgets.get(replacementType);if(!substituteWidget){const errorMsg=`Failed to replace ${type} with ${replacementType}`;throw new perseusCore.PerseusError(errorMsg,perseusCore.Errors.Internal)}registerWidget(type,substituteWidget);};const replaceDeprecatedWidgets=()=>{replaceWidget("transformer","deprecated-standin");replaceWidget("lights-puzzle","deprecated-standin");replaceWidget("reaction-diagram","deprecated-standin");replaceWidget("sequence","deprecated-standin");replaceWidget("simulator","deprecated-standin");replaceWidget("unit-input","deprecated-standin");replaceWidget("passage","deprecated-standin");replaceWidget("passage-ref","deprecated-standin");replaceWidget("passage-ref-target","deprecated-standin");};const registerEditors=editorsToRegister=>{editorsToRegister.forEach(editor=>{if(!editor.widgetName){throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`,perseusCore.Errors.Internal)}editors.set(editor.widgetName,editor);});};const replaceEditor=(type,replacementType)=>{const substituteEditor=editors.get(replacementType);if(!substituteEditor&&Log){const errorMsg=`Failed to replace editor ${type} with ${replacementType}`;Log.error(errorMsg,perseusCore.Errors.Internal);return}editors.set(type,substituteEditor);};const replaceDeprecatedEditors=()=>{replaceEditor("transformer","deprecated-standin");replaceEditor("lights-puzzle","deprecated-standin");replaceEditor("reaction-diagram","deprecated-standin");replaceEditor("sequence","deprecated-standin");replaceEditor("simulator","deprecated-standin");replaceEditor("unit-input","deprecated-standin");replaceEditor("passage","deprecated-standin");replaceEditor("passage-ref","deprecated-standin");replaceEditor("passage-ref-target","deprecated-standin");};const getWidget=type=>{const widget=widgets.get(type);if(widget==null){return null}if(widget.getWidget){return widget.getWidget()}return widget.widget};const getWidgetExport=type=>{return widgets.get(type)??null};const getEditor=type=>{return editors.get(type)??null};const getPublicWidgets=()=>{return widgets.entries().reduce((acc,[key,value])=>{if(process.env.STORYBOOK||!value.hidden){acc[key]=value;}return acc},{})};const getAllWidgetTypes=()=>{return widgets.keys()};const supportsStaticMode=type=>{const widgetInfo=widgets.get(type);return widgetInfo&&widgetInfo.getCorrectUserInput!=null};const supportsUngraded=type=>{const widgetInfo=widgets.get(type);return widgetInfo?.supportsUngraded===true};const getTracking=type=>{const widgetExport=widgets.get(type);return widgetExport&&widgetExport.tracking||DEFAULT_TRACKING};const isLintable=type=>{const widgetExports=widgets.get(type);return widgetExports&&widgetExports.isLintable||DEFAULT_LINTABLE};
1705
1705
 
1706
1706
  var widgets$1 = /*#__PURE__*/Object.freeze({
1707
1707
  __proto__: null,
@@ -1709,8 +1709,6 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
1709
1709
  getEditor: getEditor,
1710
1710
  getPublicWidgets: getPublicWidgets,
1711
1711
  getTracking: getTracking,
1712
- getVersion: getVersion,
1713
- getVersionVector: getVersionVector,
1714
1712
  getWidget: getWidget,
1715
1713
  getWidgetExport: getWidgetExport,
1716
1714
  isLintable: isLintable,
@@ -1727,7 +1725,7 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
1727
1725
 
1728
1726
  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
1727
 
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$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)"}};
1728
+ 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
1729
 
1732
1730
  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
1731
  ${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,47 +1733,47 @@ const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;const Inp
1735
1733
 
1736
1734
  const getPromptJSON$p=widgetData=>{return {type:"numeric-input",label:widgetData.labelText,userInput:{value:widgetData.userInput.currentValue}}};
1737
1735
 
1738
- var styles$y = {"inputWithExamples":"perseus_QUlWSKE-","isFocused":"perseus_8i8MUC5K","rightAlign":"perseus_9cRSmuw9","sizeSmall":"perseus_LbMErCm0"};
1736
+ var styles$z = {"inputWithExamples":"perseus_QUlWSKE-","isFocused":"perseus_8i8MUC5K","rightAlign":"perseus_9cRSmuw9","sizeSmall":"perseus_LbMErCm0"};
1739
1737
 
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"}};
1738
+ 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
1739
 
1742
1740
  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
1741
 
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(" ")})});
1742
+ 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
1743
 
1746
1744
  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
1745
 
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};
1746
+ 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
1747
 
1750
1748
  const MathRenderingContext=React__namespace.createContext({shouldAddAriaLabels:false});
1751
1749
 
1752
1750
  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
1751
 
1754
- var styles$v = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1752
+ var styles$w = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
1755
1753
 
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;
1754
+ 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
1755
 
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"};
1756
+ 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
1757
 
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})]})};
1758
+ 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
1759
 
1762
- var styles$t = {"choice":"perseus_hm3uu-sq","is-correct":"perseus_qpU2z5U7","isCorrect":"perseus_qpU2z5U7","is-wrong":"perseus_dUXUrBDI","isWrong":"perseus_dUXUrBDI"};
1760
+ var styles$u = {"choice":"perseus_hm3uu-sq","is-correct":"perseus_qpU2z5U7","isCorrect":"perseus_qpU2z5U7","is-wrong":"perseus_dUXUrBDI","isWrong":"perseus_dUXUrBDI"};
1763
1761
 
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]})};
1762
+ 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
1763
 
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"};
1764
+ 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
1765
 
1768
1766
  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
1767
 
1770
1768
  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
1769
 
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})};
1770
+ 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
1771
 
1774
1772
  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
1773
 
1776
1774
  const RadioWidget=React.forwardRef(function RadioWidget(props,ref){const{multipleSelect=false,countChoices=false,showSolutions="none",apiOptions,handleUserInput,trackInteraction,findWidgets,reviewMode,widgetId}=props;const{strings}=usePerseusI18n();const{analytics}=useDependencies();const randomSeed=(props.problemNum??0)+(props.widgetIndex??0);const choices=React.useMemo(()=>{return [...choiceTransform(props.choices,props.randomize,strings,randomSeed)]},[props.choices,props.randomize,strings,randomSeed]);wonderBlocksCore.useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:multipleSelect?"multiple-select":"single-select",widgetType:"radio",widgetId:widgetId}});});React.useImperativeHandle(ref,()=>({getPromptJSON:()=>{return getPromptJSON$o({...props,choices},props.userInput)},getSerializedState(){const{userInput:_,randomize:__,static:___,...rest}=props;return {...rest,numCorrect:props.numCorrect??0,choices,hasNoneOfTheAbove:props.hasNoneOfTheAbove??false,choiceStates:choices.map(choice=>{const selected=props.userInput?.selectedChoiceIds.includes(choice?.id)??false;return {selected,highlighted:false,readOnly:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}})}}}),[choices,props]);const renderContent=(content="")=>{const linterContext={contentType:"radio",highlightLint:false,stack:[]};return jsxRuntimeExports.jsx(MathRenderingContext.Provider,{value:{shouldAddAriaLabels:true},children:jsxRuntimeExports.jsx(Renderer,{content:content,findExternalWidgets:findWidgets,alwaysUpdate:true,linterContext:linterContext,strings:strings},"choiceContentRenderer")})};const handleChoiceChange=(choiceId,newCheckedState)=>{const checkedChoiceIds=[];const choiceStates=choices.map(choice=>{return {selected:props.userInput?.selectedChoiceIds.includes(choice.id)??false,id:choice.id}});const currentSelectedIds=choiceStates.filter(choice=>choice.selected).map(choice=>choice.id);if(newCheckedState&&!multipleSelect){checkedChoiceIds.push(choiceId);}else if(newCheckedState&&multipleSelect){checkedChoiceIds.push(...currentSelectedIds,choiceId);}else {checkedChoiceIds.push(...currentSelectedIds.filter(id=>id!==choiceId));}handleUserInput({selectedChoiceIds:checkedChoiceIds});trackInteraction();announceChoiceChange(checkedChoiceIds.length);};const announceChoiceChange=newCheckedCount=>{let screenReaderMessage="";if(!props.multipleSelect){screenReaderMessage=newCheckedCount===0?strings.notSelected:"";}else {screenReaderMessage=strings.choicesSelected({num:newCheckedCount});}wonderBlocksAnnouncer.announceMessage({message:screenReaderMessage});if(props.multipleSelect){setTimeout(()=>{wonderBlocksAnnouncer.announceMessage({message:""});},300);}};const buildChoiceProps=choiceStates=>{return choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected=false}=choiceStates[i]??{};return {id:choice.id,content:renderContent(content),checked:selected,correct:!!choice.correct,hasRationale:!!choice.rationale,rationale:renderContent(choice.rationale),isNoneOfTheAbove:!!choice.isNoneOfTheAbove}})};const prepareChoicesProps=()=>{const choiceStates=choices.map(choice=>{return {selected:props.userInput?.selectedChoiceIds.includes(choice.id)??false}});const processedChoiceStates=getChoiceStates({choices,showSolutions,choiceStates,reviewMode});return buildChoiceProps(processedChoiceStates)};const choicesProps=prepareChoicesProps();const numCorrect=props.numCorrect;const isReviewMode=reviewMode||showSolutions==="all";const onChoiceChange=apiOptions.readOnly||isReviewMode?()=>{}:handleChoiceChange;return jsxRuntimeExports.jsx(RadioComponent,{reviewMode:isReviewMode,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:choicesProps,onChoiceChange:onChoiceChange})});let Radio$1 = class Radio extends React__namespace.Component{getSerializedState(){if(!this.radioRef.current){throw new Error("Radio widget is not mounted; getSerializedState is unavailable.")}return this.radioRef.current.getSerializedState()}getPromptJSON(){if(!this.radioRef.current){throw new Error("Radio widget is not mounted; getPromptJSON is unavailable.")}return this.radioRef.current.getPromptJSON()}render(){return jsxRuntimeExports.jsx(RadioWidget,{ref:this.radioRef,...this.props})}constructor(...args){super(...args),this.radioRef=React__namespace.createRef();}};
1777
1775
 
1778
- function getStartUserInput$g(){return {selectedChoiceIds:[]}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,getStartUserInput: getStartUserInput$g,version:perseusCore.radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState)}};
1776
+ function getStartUserInput$g(){return {selectedChoiceIds:[]}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,getStartUserInput: getStartUserInput$g,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState)}};
1779
1777
 
1780
1778
  var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
1781
1779
 
@@ -1785,7 +1783,7 @@ const{radioBorderColor,checkedColor,circleSize,radioMarginWidth}=constants;var s
1785
1783
 
1786
1784
  const getPromptJSON$n=widgetData=>{return {type:"categorizer",options:{items:widgetData.items,categories:widgetData.categories},userInput:{itemToCategoryMapping:widgetData.userInput.values}}};
1787
1785
 
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};
1786
+ 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
1787
 
1790
1788
  const isFileProtocol=protocol=>{if(protocol&&protocol.toLowerCase()==="file:"){return true}return false};
1791
1789
 
@@ -1795,15 +1793,15 @@ const getUnsupportedPromptJSON=(widgetType,message="")=>{return {type:widgetType
1795
1793
 
1796
1794
  const getPromptJSON$m=()=>{return getUnsupportedPromptJSON("cs-program")};
1797
1795
 
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};
1796
+ 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
1797
 
1800
1798
  const getPromptJSON$l=widgetData=>{return {type:"definition",definition:widgetData.definition,togglePrompt:widgetData.togglePrompt}};
1801
1799
 
1802
- var styles$p = {"definition":"perseus_5CDFHduT"};
1800
+ var styles$q = {"definition":"perseus_5CDFHduT"};
1803
1801
 
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)"}};
1802
+ 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
1803
 
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};
1804
+ 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
1805
 
1808
1806
  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
1807
 
@@ -1815,100 +1813,29 @@ function sharedInitializeUserInput(widgetOptions,problemNum){const startUserInpu
1815
1813
 
1816
1814
  const getPromptJSON$j=widgetData=>{return {type:"explanation",showPrompt:widgetData.showPrompt,explanation:widgetData.explanation}};
1817
1815
 
1818
- var styles$n = {"content":"perseus_HDIlPzEz","contentCollapsed":"perseus_NkFQFgcZ","contentExpanded":"perseus_XhV-9haB","contentWrapper":"perseus_WEJESS6h","transitionCollapsed":"perseus_sbBrAODD","transitionExpanded":"perseus_Wp72j6qk"};
1816
+ var styles$o = {"content":"perseus_HDIlPzEz","contentCollapsed":"perseus_NkFQFgcZ","contentExpanded":"perseus_XhV-9haB","contentWrapper":"perseus_WEJESS6h","transitionCollapsed":"perseus_sbBrAODD","transitionExpanded":"perseus_Wp72j6qk"};
1819
1817
 
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"}};
1818
+ 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
1819
 
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};
1820
+ 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
1821
 
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}});
1822
+ 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
1823
 
1826
1824
  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
1825
 
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}};
1826
+ 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
1827
 
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};
1828
+ 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
1829
 
1832
1830
  const getPromptJSON$h=(widgetData,activeGroupJSON)=>{return {type:"graded-group-set",options:{groupCount:widgetData.gradedGroups.length,currentGroup:activeGroupJSON}}};
1833
1831
 
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"}});
1832
+ 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
1833
 
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"}});
1834
+ 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",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
1835
 
1838
1836
  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
1837
 
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
-
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
-
1844
- const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
1845
-
1846
- class Group extends React__namespace.Component{componentDidMount(){this.forceUpdate();}getPromptJSON(){return getPromptJSON$f(this.rendererRef?.getPromptJSON())}getInputPaths(){return this.rendererRef?.getInputPaths()??[]}focus(){return this.rendererRef?.focus()??false}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}};return jsxRuntimeExports.jsx("div",{className:classNames__default.default({"perseus-group":true}),children:jsxRuntimeExports.jsx(Renderer,{userInput:this.props.userInput,handleUserInput:(widgetId,userInput)=>{this.props.handleUserInput({...this.props.userInput,[widgetId]:userInput});},content:this.props.content,widgets:this.props.widgets,images:this.props.images,ref:ref=>this.rendererRef=ref,apiOptions:apiOptions,findExternalWidgets:this.props.findWidgets,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,linterContext:this.props.linterContext,strings:this.context.strings})})}constructor(...args){super(...args),this.getSerializedState=()=>{return this.rendererRef?.getSerializedState()},this.focusInputPath=path=>{this.rendererRef?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef?.blurPath(path);};}}Group.contextType=PerseusI18nContext;Group.defaultProps={content:"",widgets:{},images:{},linterContext:PerseusLinter.linterContextDefault};function getStartUserInput$a(options,problemNum){return sharedInitializeUserInput(options.widgets,problemNum)}function getUserInputFromSerializedState$a(serializedState,widgetOptions){return deriveUserInputFromSerializedState(serializedState,widgetOptions.widgets)}var Group$1 = {name:"group",displayName:"Group (SAT only)",widget:Group,hidden:true,isLintable:true,getStartUserInput: getStartUserInput$a,getUserInputFromSerializedState: getUserInputFromSerializedState$a};
1847
-
1848
- const getPromptJSON$e=()=>{return getUnsupportedPromptJSON("iframe")};
1849
-
1850
- const{updateQueryString}=Util;class Iframe extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$e()}getSerializedState(){const{userInput:_,alignment:__,...rest}=this.props;return rest}render(){const style={width:String(this.props.width),height:String(this.props.height)};const{InitialRequestUrl}=getDependencies();Object.entries(style).forEach(([key,value])=>{if(!value.endsWith("%")&&!value.endsWith("px")){style[key]=value+"px";}});let url=this.props.url;if(url&&url.length&&url.indexOf("http")!==0){url="https://www.khanacademy.org/computer-programming/program/"+url+"/embedded?buttons=no&embed=yes&editor=no&author=no";url=updateQueryString(url,"width",`${this.props.width}`);url=updateQueryString(url,"height",`${this.props.height}`);url=updateQueryString(url,"origin",InitialRequestUrl.origin);}if(this.context?.locale&&url?.includes("khanacademy.org")){url=updateQueryString(url,"lang",this.context.locale);}if(this.props.settings){const settings={};this.props.settings.forEach(setting=>{if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString(url,"settings",JSON.stringify(settings));}let sandboxProperties="allow-same-origin allow-scripts";sandboxProperties+=" allow-top-navigation";return jsxRuntimeExports.jsx("iframe",{title:this.context.strings.embeddedContent,sandbox:sandboxProperties,style:style,src:url,allowFullScreen:this.props.allowFullScreen})}constructor(...args){super(...args),this.handleMessageEvent=e=>{let data={};try{data=JSON.parse(e.originalEvent.data);}catch{return}if(data.testsPassed===undefined){return}const status=data.testsPassed?"correct":"incorrect";this.props.handleUserInput({status:status,message:data.message});};}}Iframe.contextType=PerseusI18nContext;Iframe.defaultProps={allowFullScreen:false,allowTopNavigation:false,userInput:{status:"incomplete",message:null}};function getUserInputFromSerializedState$9(serializedState){return {status:serializedState.status,message:serializedState.message}}function getStartUserInput$9(){return {status:"incomplete",message:null}}var Iframe$1 = {name:"iframe",displayName:"Iframe (deprecated)",widget:Iframe,hidden:true,getStartUserInput: getStartUserInput$9,getUserInputFromSerializedState: getUserInputFromSerializedState$9};
1851
-
1852
- const getPromptJSON$d=widgetData=>{return {type:"image",options:{altText:widgetData.alt,title:widgetData.title,caption:widgetData.caption,imageUrl:widgetData.backgroundImage.url}}};
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"};
1855
-
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
-
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}}});
1859
-
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
-
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}});
1863
-
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
-
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"}});
1867
-
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
-
1870
- const{firstNumericalParse,captureScratchpadTouchStart}=Util;const toNumericString=kmath.KhanMath.toNumericString;const getNumericFormat=kmath.KhanMath.getNumericFormat;class NumberInput extends React__namespace.Component{componentDidMount(){const value=this.getValue();if(this.props.allowPiTruncation&&value!==null&&value!==0){if(this.state.format!=="pi"&&isPiMultiple(value)){this._setValue(value/Math.PI,"pi");this.setState({format:"pi"});}}}componentDidUpdate(prevProps){if(!kmath.number.equal(this.getValue(),this.props.value)){this._setValue(this.props.value,this.state.format);}}render(){let classes=classNames__default.default({"number-input":true,"invalid-input":!this._checkValidity(this.props.value),mini:this.props.size==="mini",small:this.props.size==="small",normal:this.props.size==="normal"});if(this.props.className!=null){classes=classes+" "+this.props.className;}const{onFormatChange:_,checkValidity:__,useArrowKeys:___,allowPiTruncation:____,...restProps}=this.props;return jsxRuntimeExports.jsx("input",{...restProps,className:classes,type:"text",ref:this.inputRef,onChange:this._handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur,onKeyPress:this._handleBlur,onKeyDown:this._onKeyDown,onTouchStart:captureScratchpadTouchStart,defaultValue:toNumericString(this.props.value,this.state.format),value:undefined})}constructor(...args){super(...args),this.inputRef=React__namespace.createRef(),this.state={format:this.props.format},this._getInput=()=>{if(!this.inputRef.current){throw new perseusCore.PerseusError("Input ref accessed before set",perseusCore.Errors.Internal)}return this.inputRef.current},this.getValue=()=>{return this.parseInputValue(this._getInput().value)},this.getStringValue=()=>{return this._getInput().toString()},this.parseInputValue=value=>{if(value===""){const placeholder=this.props.placeholder;return ___default.default.isFinite(placeholder)?+placeholder:null}const result=firstNumericalParse(value);return ___default.default.isFinite(result)?result:this.props.value},this.focus=()=>{this._getInput().focus();this._handleFocus();},this.blur=()=>{this._getInput().blur();this._handleBlur();},this.setSelectionRange=(selectionStart,selectionEnd)=>{this._getInput().setSelectionRange(selectionStart,selectionEnd);},this.getSelectionStart=()=>{return this._getInput().selectionStart},this.getSelectionEnd=()=>{return this._getInput().selectionEnd},this._checkValidity=value=>{if(value==null){return true}const val=firstNumericalParse(value);const checkValidity=this.props.checkValidity;return ___default.default.isFinite(val)&&checkValidity(val)},this._handleChange=e=>{const text=e.target.value;const value=this.parseInputValue(text);const format=getNumericFormat(text);this.props.onChange(value);if(format){this.props.onFormatChange(value,format);this.setState({format:format});}},this._handleFocus=()=>{if(this.props.onFocus){this.props.onFocus();}},this._handleBlur=e=>{if(e&&e.type==="keypress"&&e.keyCode!==13){return}this._setValue(this.props.value,this.state.format);if(this.props.onBlur){this.props.onBlur();}},this._onKeyDown=e=>{if(this.props.onKeyDown){this.props.onKeyDown(e);}if(!this.props.useArrowKeys||!___default.default.contains(["ArrowUp","ArrowDown"],e.key)){return}let val=this.getValue();if(val!==Math.floor(val)){return}if(e.key==="ArrowUp"){val=val+1;}else if(e.key==="ArrowDown"){val=val-1;}if(this._checkValidity(val)){this.props.onChange(val);}},this._setValue=(val,format)=>{this._getInput().value=toNumericString(val,format);};}}NumberInput.propTypes={value:PropTypes__default.default.number,format:PropTypes__default.default.string,placeholder:PropTypes__default.default.oneOfType([PropTypes__default.default.string,PropTypes__default.default.number]),onChange:PropTypes__default.default.func.isRequired,onFormatChange:PropTypes__default.default.func,checkValidity:PropTypes__default.default.func,size:PropTypes__default.default.oneOf(["mini","small","normal"]),label:PropTypes__default.default.oneOf(["put your labels outside your inputs!"]),allowPiTruncation:PropTypes__default.default.bool};NumberInput.defaultProps={value:null,placeholder:null,format:null,onFormatChange:()=>null,checkValidity:()=>true,useArrowKeys:false};
1871
-
1872
- const truth=()=>true;class RangeInput extends React__namespace.Component{render(){const value=this.props.value;const checkValidity=this.props.checkValidity||truth;return jsxRuntimeExports.jsxs("div",{className:"range-input",children:[jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[0],checkValidity:val=>checkValidity([val,value[1]]),onChange:this.onChange.bind(this,0),placeholder:this.props.placeholder[0],allowPiTruncation:this.props.allowPiTruncation}),jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[1],checkValidity:val=>checkValidity([value[0],val]),onChange:this.onChange.bind(this,1),placeholder:this.props.placeholder[1],allowPiTruncation:this.props.allowPiTruncation})]})}constructor(...args){super(...args),this.onChange=(i,newVal)=>{const value=this.props.value;if(i===0){this.props.onChange([newVal,value[1]]);}else {this.props.onChange([value[0],newVal]);}};}}RangeInput.propTypes={value:PropTypes__default.default.array.isRequired,onChange:PropTypes__default.default.func.isRequired,placeholder:PropTypes__default.default.array,checkValidity:PropTypes__default.default.func,allowPiTruncation:PropTypes__default.default.bool};RangeInput.defaultProps={placeholder:[null,null]};
1873
-
1874
- const textWidthCache={};function getTextWidth(text){if(!textWidthCache[text]){const $test=$__default.default("<span>").text(text).appendTo("body");textWidthCache[text]=$test.width()+5;$test.remove();}return textWidthCache[text]}class TextListEditor extends React__namespace.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({items:nextProps.options.concat("")});}render(){const className=["perseus-text-list-editor","perseus-clearfix","layout-"+this.props.layout].join(" ");const inputs=___default.default.map(this.state.items,function(item,i){return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsx("input",{ref:"input_"+i,type:"text",value:item,onChange:this.onChange.bind(this,i),onKeyDown:this.onKeyDown.bind(this,i),style:{width:getTextWidth(item)}})},i)},this);return jsxRuntimeExports.jsx("ul",{className:className,children:inputs})}constructor(...args){super(...args),this.state={items:this.props.options.concat("")},this.onChange=(index,event)=>{let items=___default.default.clone(this.state.items);items[index]=event.target.value;if(index===items.length-1){items=items.concat("");}this.setState({items:items});this.props.onChange(___default.default.compact(items));},this.onKeyDown=(index,event)=>{const which=event.nativeEvent.keyCode;if(which===8&&this.state.items[index]===""){event.preventDefault();const items=___default.default.clone(this.state.items);const focusIndex=index===0?0:index-1;if(index===items.length-1&&(index===0||items[focusIndex]!=="")){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();}else {items.splice(index,1);this.setState({items:items},function(){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();});}}else if(which===8&&this.state.items[index].length===1&&index===this.state.items.length-2){event.preventDefault();const items=___default.default.clone(this.state.items);items.splice(index,1);this.setState({items:items});this.props.onChange(___default.default.compact(items));}else if(which===13){event.preventDefault();const items=___default.default.clone(this.state.items);const focusIndex=index+1;if(index===items.length-2){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();}else {items.splice(focusIndex,0,"");this.setState({items:items},function(){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();});}}};}}TextListEditor.propTypes={options:PropTypes__default.default.array,layout:PropTypes__default.default.oneOf(["horizontal","vertical"]),onChange:PropTypes__default.default.func.isRequired};TextListEditor.defaultProps={options:[],layout:"horizontal"};
1875
-
1876
- var components = /*#__PURE__*/Object.freeze({
1877
- __proto__: null,
1878
- ButtonGroup: ButtonGroup,
1879
- Graphie: Graphie,
1880
- HUD: HUD,
1881
- Icon: Icon,
1882
- InfoTip: InfoTip,
1883
- InlineIcon: InlineIcon,
1884
- MathInput: MathInput,
1885
- MultiButtonGroup: MultiButtonGroup,
1886
- NumberInput: NumberInput,
1887
- RangeInput: RangeInput,
1888
- SvgImage: SvgImage,
1889
- TextInput: TextInput,
1890
- TextListEditor: TextListEditor
1891
- });
1892
-
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
-
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,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}};
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%"}};
1898
-
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
-
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})})]})};
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,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})]})};
1904
-
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
-
1907
- const getPromptJSON$c=()=>{return getUnsupportedPromptJSON("interaction")};
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,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
-
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)}};
1838
+ const getPromptJSON$f=(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
1839
 
1913
1840
  const X=0;const Y=1;
1914
1841
 
@@ -1948,13 +1875,13 @@ const hitboxSizePx$1=48;const MovablePointView=React.forwardRef(function Movable
1948
1875
 
1949
1876
  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
1877
 
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]})});
1878
+ const MovablePoint$3=React__namespace.forwardRef(function MovablePointWithRef(props,pointRef){const{visiblePoint,focusableHandle}=useControlPoint({...props,forwardedRef:pointRef});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[focusableHandle,visiblePoint]})});
1952
1879
 
1953
1880
  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
1881
 
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}}
1882
+ 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$3,{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
1883
 
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)}}
1884
+ 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$1(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$1(props,newCoords)}function getLinearSystemCoords$1(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return pointsFromNormalized$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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
1885
 
1959
1886
  function pathBuilder(){return new PathBuilder}class PathBuilder{build(){return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("")}move(x,y){this.path.push({action:"M",args:[x,y]});return this}line(x,y){this.path.push({action:"L",args:[x,y]});return this}circularArc(radius,toX,toY,{sweep=false,largeArc=false}={}){this.path.push({action:"A",args:[radius,radius,0,largeArc?1:0,sweep?1:0,toX,toY]});return this}curve(control1X,control1Y,control2X,control2Y,endX,endY){this.path.push({action:"C",args:[control1X,control1Y,control2X,control2Y,endX,endY]});return this}scale(factor){this.scaleFactor*=factor;return this}constructor(){this.path=[];this.scaleFactor=1;}}function commandToString(command){return `${command.action}${command.args.join(" ")}`}function scaleCommandBy(scaleFactor){return command=>{switch(command.action){case "A":return {...command,args:[command.args[0]*scaleFactor,command.args[1]*scaleFactor,command.args[2],command.args[3],command.args[4],command.args[5]*scaleFactor,command.args[6]*scaleFactor]};default:return {...command,args:command.args.map(c=>c*scaleFactor)}}}}
1960
1887
 
@@ -1968,6 +1895,41 @@ const tickSize=10;const tickLabelSize=14;const YGridTick=({y,range,tickStep,show
1968
1895
 
1969
1896
  const axisOptions=(props,axisIndex)=>{const lines=props.markings==="axes"?false:props.gridStep[axisIndex];return {axis:props.markings==="graph"||props.markings==="axes",lines:lines,labels:false}};const Grid=props=>{return props.markings==="none"?null:jsxRuntimeExports.jsx(mafs.Coordinates.Cartesian,{xAxis:axisOptions(props,X),yAxis:axisOptions(props,Y)})};
1970
1897
 
1898
+ const VisibleIcon=()=>jsxRuntimeExports.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",className:aphrodite.css(styles$h.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$h.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$h.enabled;icon=jsxRuntimeExports.jsx(VisibleIcon,{});}else {state=styles$h.disabled;icon=jsxRuntimeExports.jsx(HiddenIcon,{});}return jsxRuntimeExports.jsxs("button",{className:aphrodite.css(styles$h.hud,fixedPosition&&styles$h.hudFixedPosition,state),onClick:e=>{onClick();},children:[icon,message]})};const styles$h=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}}});
1899
+
1900
+ 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"};
1901
+
1902
+ const InfoTipBase=props=>{return jsxRuntimeExports.jsx(Tooltip__default.default,{content:jsxRuntimeExports.jsx(wonderBlocksTypography.BodyText,{style:styles$g.body,children:props.children}),placement:"right",children:jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{size:"small",icon:questionIcon__default.default,style:styles$g.spacingLeft})})};const styles$g=aphrodite.StyleSheet.create({spacingLeft:{marginInlineStart:wonderBlocksTokens.spacing.xxxSmall_4},body:{padding:wonderBlocksTokens.spacing.medium_16}});
1903
+
1904
+ 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};}}
1905
+
1906
+ 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$f.buttonStyle,selected&&styles$f.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$f=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"}});
1907
+
1908
+ 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}
1909
+
1910
+ const{firstNumericalParse,captureScratchpadTouchStart}=Util;const toNumericString=kmath.KhanMath.toNumericString;const getNumericFormat=kmath.KhanMath.getNumericFormat;class NumberInput extends React__namespace.Component{componentDidMount(){const value=this.getValue();if(this.props.allowPiTruncation&&value!==null&&value!==0){if(this.state.format!=="pi"&&isPiMultiple(value)){this._setValue(value/Math.PI,"pi");this.setState({format:"pi"});}}}componentDidUpdate(prevProps){if(!kmath.number.equal(this.getValue(),this.props.value)){this._setValue(this.props.value,this.state.format);}}render(){let classes=classNames__default.default({"number-input":true,"invalid-input":!this._checkValidity(this.props.value),mini:this.props.size==="mini",small:this.props.size==="small",normal:this.props.size==="normal"});if(this.props.className!=null){classes=classes+" "+this.props.className;}const{onFormatChange:_,checkValidity:__,useArrowKeys:___,allowPiTruncation:____,...restProps}=this.props;return jsxRuntimeExports.jsx("input",{...restProps,className:classes,type:"text",ref:this.inputRef,onChange:this._handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur,onKeyPress:this._handleBlur,onKeyDown:this._onKeyDown,onTouchStart:captureScratchpadTouchStart,defaultValue:toNumericString(this.props.value,this.state.format),value:undefined})}constructor(...args){super(...args),this.inputRef=React__namespace.createRef(),this.state={format:this.props.format},this._getInput=()=>{if(!this.inputRef.current){throw new perseusCore.PerseusError("Input ref accessed before set",perseusCore.Errors.Internal)}return this.inputRef.current},this.getValue=()=>{return this.parseInputValue(this._getInput().value)},this.getStringValue=()=>{return this._getInput().toString()},this.parseInputValue=value=>{if(value===""){const placeholder=this.props.placeholder;return ___default.default.isFinite(placeholder)?+placeholder:null}const result=firstNumericalParse(value);return ___default.default.isFinite(result)?result:this.props.value},this.focus=()=>{this._getInput().focus();this._handleFocus();},this.blur=()=>{this._getInput().blur();this._handleBlur();},this.setSelectionRange=(selectionStart,selectionEnd)=>{this._getInput().setSelectionRange(selectionStart,selectionEnd);},this.getSelectionStart=()=>{return this._getInput().selectionStart},this.getSelectionEnd=()=>{return this._getInput().selectionEnd},this._checkValidity=value=>{if(value==null){return true}const val=firstNumericalParse(value);const checkValidity=this.props.checkValidity;return ___default.default.isFinite(val)&&checkValidity(val)},this._handleChange=e=>{const text=e.target.value;const value=this.parseInputValue(text);const format=getNumericFormat(text);this.props.onChange(value);if(format){this.props.onFormatChange(value,format);this.setState({format:format});}},this._handleFocus=()=>{if(this.props.onFocus){this.props.onFocus();}},this._handleBlur=e=>{if(e&&e.type==="keypress"&&e.keyCode!==13){return}this._setValue(this.props.value,this.state.format);if(this.props.onBlur){this.props.onBlur();}},this._onKeyDown=e=>{if(this.props.onKeyDown){this.props.onKeyDown(e);}if(!this.props.useArrowKeys||!___default.default.contains(["ArrowUp","ArrowDown"],e.key)){return}let val=this.getValue();if(val!==Math.floor(val)){return}if(e.key==="ArrowUp"){val=val+1;}else if(e.key==="ArrowDown"){val=val-1;}if(this._checkValidity(val)){this.props.onChange(val);}},this._setValue=(val,format)=>{this._getInput().value=toNumericString(val,format);};}}NumberInput.propTypes={value:PropTypes__default.default.number,format:PropTypes__default.default.string,placeholder:PropTypes__default.default.oneOfType([PropTypes__default.default.string,PropTypes__default.default.number]),onChange:PropTypes__default.default.func.isRequired,onFormatChange:PropTypes__default.default.func,checkValidity:PropTypes__default.default.func,size:PropTypes__default.default.oneOf(["mini","small","normal"]),label:PropTypes__default.default.oneOf(["put your labels outside your inputs!"]),allowPiTruncation:PropTypes__default.default.bool};NumberInput.defaultProps={value:null,placeholder:null,format:null,onFormatChange:()=>null,checkValidity:()=>true,useArrowKeys:false};
1911
+
1912
+ const truth=()=>true;class RangeInput extends React__namespace.Component{render(){const value=this.props.value;const checkValidity=this.props.checkValidity||truth;return jsxRuntimeExports.jsxs("div",{className:"range-input",children:[jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[0],checkValidity:val=>checkValidity([val,value[1]]),onChange:this.onChange.bind(this,0),placeholder:this.props.placeholder[0],allowPiTruncation:this.props.allowPiTruncation}),jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[1],checkValidity:val=>checkValidity([value[0],val]),onChange:this.onChange.bind(this,1),placeholder:this.props.placeholder[1],allowPiTruncation:this.props.allowPiTruncation})]})}constructor(...args){super(...args),this.onChange=(i,newVal)=>{const value=this.props.value;if(i===0){this.props.onChange([newVal,value[1]]);}else {this.props.onChange([value[0],newVal]);}};}}RangeInput.propTypes={value:PropTypes__default.default.array.isRequired,onChange:PropTypes__default.default.func.isRequired,placeholder:PropTypes__default.default.array,checkValidity:PropTypes__default.default.func,allowPiTruncation:PropTypes__default.default.bool};RangeInput.defaultProps={placeholder:[null,null]};
1913
+
1914
+ const textWidthCache={};function getTextWidth(text){if(!textWidthCache[text]){const $test=$__default.default("<span>").text(text).appendTo("body");textWidthCache[text]=$test.width()+5;$test.remove();}return textWidthCache[text]}class TextListEditor extends React__namespace.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({items:nextProps.options.concat("")});}render(){const className=["perseus-text-list-editor","perseus-clearfix","layout-"+this.props.layout].join(" ");const inputs=___default.default.map(this.state.items,function(item,i){return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsx("input",{ref:"input_"+i,type:"text",value:item,onChange:this.onChange.bind(this,i),onKeyDown:this.onKeyDown.bind(this,i),style:{width:getTextWidth(item)}})},i)},this);return jsxRuntimeExports.jsx("ul",{className:className,children:inputs})}constructor(...args){super(...args),this.state={items:this.props.options.concat("")},this.onChange=(index,event)=>{let items=___default.default.clone(this.state.items);items[index]=event.target.value;if(index===items.length-1){items=items.concat("");}this.setState({items:items});this.props.onChange(___default.default.compact(items));},this.onKeyDown=(index,event)=>{const which=event.nativeEvent.keyCode;if(which===8&&this.state.items[index]===""){event.preventDefault();const items=___default.default.clone(this.state.items);const focusIndex=index===0?0:index-1;if(index===items.length-1&&(index===0||items[focusIndex]!=="")){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();}else {items.splice(index,1);this.setState({items:items},function(){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();});}}else if(which===8&&this.state.items[index].length===1&&index===this.state.items.length-2){event.preventDefault();const items=___default.default.clone(this.state.items);items.splice(index,1);this.setState({items:items});this.props.onChange(___default.default.compact(items));}else if(which===13){event.preventDefault();const items=___default.default.clone(this.state.items);const focusIndex=index+1;if(index===items.length-2){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();}else {items.splice(focusIndex,0,"");this.setState({items:items},function(){ReactDOM__namespace.default.findDOMNode(this.refs["input_"+focusIndex]).focus();});}}};}}TextListEditor.propTypes={options:PropTypes__default.default.array,layout:PropTypes__default.default.oneOf(["horizontal","vertical"]),onChange:PropTypes__default.default.func.isRequired};TextListEditor.defaultProps={options:[],layout:"horizontal"};
1915
+
1916
+ var components = /*#__PURE__*/Object.freeze({
1917
+ __proto__: null,
1918
+ ButtonGroup: ButtonGroup,
1919
+ Graphie: Graphie,
1920
+ HUD: HUD,
1921
+ Icon: Icon,
1922
+ InfoTip: InfoTip,
1923
+ InlineIcon: InlineIcon,
1924
+ MathInput: MathInput,
1925
+ MultiButtonGroup: MultiButtonGroup,
1926
+ NumberInput: NumberInput,
1927
+ RangeInput: RangeInput,
1928
+ SvgImage: SvgImage,
1929
+ TextInput: TextInput,
1930
+ TextListEditor: TextListEditor
1931
+ });
1932
+
1971
1933
  const LegacyGrid=({box,backgroundImage})=>{const{url,width,height}=backgroundImage??{};if(url&&typeof url==="string"){const scale=box[X]/interactiveSizes$1.defaultBoxSize;return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:{position:"absolute",bottom:0,left:0},children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{src:url,allowZoom:false,width:width,height:height,scale:scale,responsive:false,setAssetStatus:setAssetStatus,alt:""})})})}return null};
1972
1934
 
1973
1935
  function LockedLabel(props){const{coord,text,color,size}=props;const[x,y]=pointToPixel(coord,useGraphConfig());const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LockedLabelStrokeFilter,{}),jsxRuntimeExports.jsx("span",{className:"locked-label",style:{position:"absolute",left:x,top:y,color:perseusCore.lockedFigureColors[color],fontSize:wonderBlocksTokens.font.size[size],filter:"url(#math-stroke)"},"aria-hidden":true,children:jsxRuntimeExports.jsx(TeX,{children:replaceOutsideTeX(text)})})]})}function LockedLabelStrokeFilter(){const color=wonderBlocksTokens.semanticColor.core.border.knockout.default;return jsxRuntimeExports.jsx("svg",{width:"0",height:"0",style:{position:"absolute"},children:jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsxs("filter",{id:"math-stroke",children:[jsxRuntimeExports.jsx("feMorphology",{operator:"dilate",radius:"2",in:"SourceGraphic",result:"expanded"}),jsxRuntimeExports.jsx("feFlood",{floodColor:color,result:"flood"}),jsxRuntimeExports.jsx("feComposite",{in:"flood",in2:"expanded",operator:"in",result:"outline"}),jsxRuntimeExports.jsxs("feMerge",{children:[jsxRuntimeExports.jsx("feMergeNode",{in:"outline"}),jsxRuntimeExports.jsx("feMergeNode",{in:"SourceGraphic"})]})]})})})}
@@ -2004,45 +1966,45 @@ const{clockwise: clockwise$1}=kmath.geometry;const{getAngleFromVertex: getAngleF
2004
1966
 
2005
1967
  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
1968
 
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"})]})};
1969
+ const Line$2=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
1970
 
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]})};
1971
+ const MovableLine$2=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$2,{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
1972
 
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}}
1973
+ 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$3,{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$3,{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$3,{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
1974
 
2013
1975
  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
1976
 
2015
- function renderCircleGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(CircleGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getCircleGraphDescription(state,i18n)}}function CircleGraph(props){const{dispatch,graphState}=props;const{center,pointLabels,radiusPoint,snapStep}=graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const radius=getRadius(graphState);const id=React__namespace.useId();const circleId=id+"-circle";const radiusId=id+"-radius";const outerPointsId=id+"-outer-points";const{srCircleGraph,srCircleShape,srCircleRadiusPoint,srCircleRadius,srCircleOuterPoints}=describeCircleGraph(graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srCircleGraph,"aria-describedby":`${circleId} ${radiusId} ${outerPointsId}`,children:[jsxRuntimeExports.jsx(MovableCircle,{id:circleId,ariaLabel:srCircleShape,ariaDescribedBy:`${radiusId} ${outerPointsId}`,center:center,radius:radius,onMove:c=>{dispatch(actions.circle.moveCenter(c));}}),jsxRuntimeExports.jsx(MovablePoint$1,{ariaLabel:buildLabel(0,radiusPoint)??`${srCircleRadiusPoint} ${srCircleRadius}`,ariaDescribedBy:`${outerPointsId}`,point:radiusPoint,sequenceNumber:1,cursor:"ew-resize",onMove:newRadiusPoint=>{dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));},constrain:getCircleKeyboardConstraint(center,radiusPoint,snapStep)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:radiusId,children:srCircleRadius}),jsxRuntimeExports.jsx(SRDescInSVG,{id:outerPointsId,children:srCircleOuterPoints})]})}function MovableCircle(props){const{id,ariaLabel,ariaDescribedBy,center,radius,onMove}=props;const{snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const[focused,setFocused]=React__namespace.useState(false);const focusableHandleRef=React.useRef(null);const visibleGroupRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point:center,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});const{dragging}=useDraggable({gestureTarget:visibleGroupRef,point:center,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});React__namespace.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const[centerPx]=useTransformVectorsToPixels(center);const[radiiPx]=useTransformDimensionsToPixels([radius,radius]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("g",{ref:focusableHandleRef,className:"movable-circle-focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,role:"button","aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-disabled":disableKeyboardInteraction,onFocus:()=>setFocused(true),onBlur:()=>setFocused(false)}),jsxRuntimeExports.jsxs("g",{"aria-hidden":true,ref:visibleGroupRef,className:`movable-circle ${dragging?"movable-circle--dragging":""}`,children:[jsxRuntimeExports.jsxs(ClipToGraphBounds,{children:[jsxRuntimeExports.jsx("ellipse",{className:"focus-ring",cx:centerPx[X],cy:centerPx[Y],rx:radiiPx[X]+3,ry:radiiPx[Y]+3}),jsxRuntimeExports.jsx("ellipse",{id:id,className:"circle",cx:centerPx[X],cy:centerPx[Y],rx:radiiPx[X],ry:radiiPx[Y],stroke:interactiveColor,"data-testid":"movable-circle__circle"})]}),jsxRuntimeExports.jsx(DragHandle,{center:center,dragging:dragging,focused:focused})]})]})}const dragHandleDimensions=[24,14];const dragHandleDotPositions=crossProduct([-4.4,0,4.4],[-2.1,2.1]);function DragHandle(props){const{center,dragging,focused}=props;const[centerPx]=useTransformVectorsToPixels(center);const{markings,interactiveColor}=useGraphConfig();const cornerRadius=Math.min(...dragHandleDimensions)/2;const topLeft=mafs.vec.sub(centerPx,mafs.vec.scale(dragHandleDimensions,.5));const showHairlines=(dragging||focused)&&markings!=="none";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showHairlines&&jsxRuntimeExports.jsx(Hairlines,{point:center}),jsxRuntimeExports.jsx("rect",{className:"movable-circle-handle",x:topLeft[X],y:topLeft[Y],width:dragHandleDimensions[X],height:dragHandleDimensions[Y],rx:cornerRadius,ry:cornerRadius,fill:interactiveColor,"data-testid":"movable-circle__handle"}),dragHandleDotPositions.map(offsetPx=>{const[xPx,yPx]=mafs.vec.add(offsetPx,centerPx);return jsxRuntimeExports.jsx("circle",{className:"movable-circle-handle-dot",cx:xPx,cy:yPx},`circle-${xPx}-${yPx}`)})]})}function crossProduct(as,bs){const result=[];for(const a of as){for(const b of bs){result.push([a,b]);}}return result}function getCircleGraphDescription(state,i18n){const strings=describeCircleGraph(state,i18n);return strings.srCircleInteractiveElement}const getCircleKeyboardConstraint=(center,radiusPoint,snapStep)=>{const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(radiusPoint);if(mafs.vec.dist(movedCoord,center)===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]))}};function describeCircleGraph(state,i18n){const{strings,locale}=i18n;const{center,radiusPoint}=state;const radius=getRadius(state);const srCircleGraph=strings.srCircleGraph;const srCircleShape=srCircleCenterLabel(center[0],center[1],strings,locale);const srCircleRadiusPoint=srCircleRadiusPointLabel(radiusPoint[0],radiusPoint[1],center[0],strings,locale);const srCircleRadius=strings.srCircleRadius({radius});const srCircleOuterPoints=strings.srCircleOuterPoints({point1X:srFormatNumber(center[0]+radius,locale),point1Y:srFormatNumber(center[1],locale),point2X:srFormatNumber(center[0],locale),point2Y:srFormatNumber(center[1]+radius,locale),point3X:srFormatNumber(center[0]-radius,locale),point3Y:srFormatNumber(center[1],locale),point4X:srFormatNumber(center[0],locale),point4Y:srFormatNumber(center[1]-radius,locale)});const srCircleInteractiveElement=strings.srInteractiveElements({elements:[srCircleShape,srCircleRadius].join(" ")});return {srCircleGraph,srCircleShape,srCircleRadiusPoint,srCircleRadius,srCircleOuterPoints,srCircleInteractiveElement}}
1977
+ function renderCircleGraph(state,dispatch,i18n){return {graph:jsxRuntimeExports.jsx(CircleGraph,{graphState:state,dispatch:dispatch}),interactiveElementsDescription:getCircleGraphDescription(state,i18n)}}function CircleGraph(props){const{dispatch,graphState}=props;const{center,pointLabels,radiusPoint,snapStep}=graphState;const{strings,locale}=usePerseusI18n();const buildLabel=usePointAriaLabel(pointLabels);const radius=getRadius(graphState);const id=React__namespace.useId();const circleId=id+"-circle";const radiusId=id+"-radius";const outerPointsId=id+"-outer-points";const{srCircleGraph,srCircleShape,srCircleRadiusPoint,srCircleRadius,srCircleOuterPoints}=describeCircleGraph(graphState,{strings,locale});return jsxRuntimeExports.jsxs("g",{"aria-label":srCircleGraph,"aria-describedby":`${circleId} ${radiusId} ${outerPointsId}`,children:[jsxRuntimeExports.jsx(MovableCircle,{id:circleId,ariaLabel:srCircleShape,ariaDescribedBy:`${radiusId} ${outerPointsId}`,center:center,radius:radius,onMove:c=>{dispatch(actions.circle.moveCenter(c));}}),jsxRuntimeExports.jsx(MovablePoint$3,{ariaLabel:buildLabel(0,radiusPoint)??`${srCircleRadiusPoint} ${srCircleRadius}`,ariaDescribedBy:`${outerPointsId}`,point:radiusPoint,sequenceNumber:1,cursor:"ew-resize",onMove:newRadiusPoint=>{dispatch(actions.circle.moveRadiusPoint(newRadiusPoint));},constrain:getCircleKeyboardConstraint(center,radiusPoint,snapStep)}),jsxRuntimeExports.jsx(SRDescInSVG,{id:radiusId,children:srCircleRadius}),jsxRuntimeExports.jsx(SRDescInSVG,{id:outerPointsId,children:srCircleOuterPoints})]})}function MovableCircle(props){const{id,ariaLabel,ariaDescribedBy,center,radius,onMove}=props;const{snapStep,disableKeyboardInteraction,interactiveColor}=useGraphConfig();const[focused,setFocused]=React__namespace.useState(false);const focusableHandleRef=React.useRef(null);const visibleGroupRef=React.useRef(null);useDraggable({gestureTarget:focusableHandleRef,point:center,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});const{dragging}=useDraggable({gestureTarget:visibleGroupRef,point:center,onMove,constrainKeyboardMovement:p=>snap(snapStep,p)});React__namespace.useLayoutEffect(()=>{if(dragging&&!focused){focusableHandleRef.current?.focus();}},[dragging,focused]);const[centerPx]=useTransformVectorsToPixels(center);const[radiiPx]=useTransformDimensionsToPixels([radius,radius]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("g",{ref:focusableHandleRef,className:"movable-circle-focusable-handle",tabIndex:disableKeyboardInteraction?-1:0,role:"button","aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,"aria-disabled":disableKeyboardInteraction,onFocus:()=>setFocused(true),onBlur:()=>setFocused(false)}),jsxRuntimeExports.jsxs("g",{"aria-hidden":true,ref:visibleGroupRef,className:`movable-circle ${dragging?"movable-circle--dragging":""}`,children:[jsxRuntimeExports.jsxs(ClipToGraphBounds,{children:[jsxRuntimeExports.jsx("ellipse",{className:"focus-ring",cx:centerPx[X],cy:centerPx[Y],rx:radiiPx[X]+3,ry:radiiPx[Y]+3}),jsxRuntimeExports.jsx("ellipse",{id:id,className:"circle",cx:centerPx[X],cy:centerPx[Y],rx:radiiPx[X],ry:radiiPx[Y],stroke:interactiveColor,"data-testid":"movable-circle__circle"})]}),jsxRuntimeExports.jsx(DragHandle,{center:center,dragging:dragging,focused:focused})]})]})}const dragHandleDimensions=[24,14];const dragHandleDotPositions=crossProduct([-4.4,0,4.4],[-2.1,2.1]);function DragHandle(props){const{center,dragging,focused}=props;const[centerPx]=useTransformVectorsToPixels(center);const{markings,interactiveColor}=useGraphConfig();const cornerRadius=Math.min(...dragHandleDimensions)/2;const topLeft=mafs.vec.sub(centerPx,mafs.vec.scale(dragHandleDimensions,.5));const showHairlines=(dragging||focused)&&markings!=="none";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showHairlines&&jsxRuntimeExports.jsx(Hairlines,{point:center}),jsxRuntimeExports.jsx("rect",{className:"movable-circle-handle",x:topLeft[X],y:topLeft[Y],width:dragHandleDimensions[X],height:dragHandleDimensions[Y],rx:cornerRadius,ry:cornerRadius,fill:interactiveColor,"data-testid":"movable-circle__handle"}),dragHandleDotPositions.map(offsetPx=>{const[xPx,yPx]=mafs.vec.add(offsetPx,centerPx);return jsxRuntimeExports.jsx("circle",{className:"movable-circle-handle-dot",cx:xPx,cy:yPx},`circle-${xPx}-${yPx}`)})]})}function crossProduct(as,bs){const result=[];for(const a of as){for(const b of bs){result.push([a,b]);}}return result}function getCircleGraphDescription(state,i18n){const strings=describeCircleGraph(state,i18n);return strings.srCircleInteractiveElement}const getCircleKeyboardConstraint=(center,radiusPoint,snapStep)=>{const movePointWithConstraint=moveFunc=>{let movedCoord=moveFunc(radiusPoint);if(mafs.vec.dist(movedCoord,center)===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]))}};function describeCircleGraph(state,i18n){const{strings,locale}=i18n;const{center,radiusPoint}=state;const radius=getRadius(state);const srCircleGraph=strings.srCircleGraph;const srCircleShape=srCircleCenterLabel(center[0],center[1],strings,locale);const srCircleRadiusPoint=srCircleRadiusPointLabel(radiusPoint[0],radiusPoint[1],center[0],strings,locale);const srCircleRadius=strings.srCircleRadius({radius});const srCircleOuterPoints=strings.srCircleOuterPoints({point1X:srFormatNumber(center[0]+radius,locale),point1Y:srFormatNumber(center[1],locale),point2X:srFormatNumber(center[0],locale),point2Y:srFormatNumber(center[1]+radius,locale),point3X:srFormatNumber(center[0]-radius,locale),point3Y:srFormatNumber(center[1],locale),point4X:srFormatNumber(center[0],locale),point4Y:srFormatNumber(center[1]-radius,locale)});const srCircleInteractiveElement=strings.srInteractiveElements({elements:[srCircleShape,srCircleRadius].join(" ")});return {srCircleGraph,srCircleShape,srCircleRadiusPoint,srCircleRadius,srCircleOuterPoints,srCircleInteractiveElement}}
2016
1978
 
2017
1979
  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
1980
 
2019
1981
  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
1982
 
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})})}}
1983
+ 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$3,{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
1984
 
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}}
1985
+ 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$2,{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
1986
 
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(" ")})}
1987
+ 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$2,{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
1988
 
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})})}}
1989
+ 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$3,{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
1990
 
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(" ")})}
1991
+ 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$3,{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$3,{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
1992
 
2031
1993
  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
1994
 
2033
1995
  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
1996
 
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]))}}
1997
+ 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$3,{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$3,{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
1998
 
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};
1999
+ 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$3,{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
2000
 
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}}
2001
+ 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$2,{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
2002
 
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(" ")})}
2003
+ 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$2,{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
2004
 
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}}
2005
+ 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$3,{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
2006
 
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}}
2007
+ 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$3,{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
2008
 
2047
2009
  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
2010
 
@@ -2052,13 +2014,49 @@ const{calculateAngleInDegrees: calculateAngleInDegrees$1}=kmath.angles;const LIN
2052
2014
 
2053
2015
  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
2016
 
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}
2017
+ 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
2018
 
2057
2019
  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
2020
 
2059
2021
  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
2022
 
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};
2023
+ const defaultBackgroundImage$1={url:null};class InteractiveGraph extends React__namespace.Component{static getEquationString(props){return getEquationString$1(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$f(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$1,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"none"}};function getUserInputFromSerializedState$b(serializedState){return serializedState.graph}function getStartUserInput$b(options){return options.graph}function getCorrectUserInput$5(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$b,getCorrectUserInput: getCorrectUserInput$5,getUserInputFromSerializedState: getUserInputFromSerializedState$b,supportsUngraded:true};
2024
+
2025
+ const movableTypeToComponent={PLOT:Graphie.Plot,PARABOLA:Graphie.Parabola,SINUSOID:Graphie.Sinusoid};const DEFAULT_BACKGROUND_IMAGE={url:null};const getEquationString=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=(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(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})}};
2026
+
2027
+ const MovablePoint$2=Graphie.MovablePoint;const MovableLine$1=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$2,{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$1,{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$2,{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}}getAvailableTypes(){if(this.props.static){invariant__default.default(this.props.correct,"static widgets must have a correct answer");return [this.props.correct.type]}return this.props.availableTypes}renderLegacyGrapher(){const availableTypes=this.getAvailableTypes();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]})}render(){if(!this.props.apiOptions.flags?.["grapher-to-interactive-graph"]){return this.renderLegacyGrapher()}const interactiveGraphOptions=perseusCore.convertGrapherOptionsToInteractiveGraph(this.props);if(interactiveGraphOptions==null){return this.renderLegacyGrapher()}const interactiveGraphUserInput=perseusCore.convertGrapherUserInputToInteractiveGraph(this.props.userInput);return jsxRuntimeExports.jsx(InteractiveGraph$1.widget,{...this.props,...interactiveGraphOptions,userInput:interactiveGraphUserInput,handleUserInput:interactiveGraphUserInput=>this.props.handleUserInput(perseusCore.convertInteractiveGraphUserInputToGrapher(interactiveGraphUserInput))})}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$a(serializedState){return serializedState.plot}function getStartUserInput$a(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$4(options){invariant__default.default(options.correct,"getCorrectUserInput should only be called for static widgets");return options.correct}const WrappedGrapher=withDependencies(Grapher);var Grapher$1 = {name:"grapher",displayName:"Grapher",hidden:true,widget:WrappedGrapher,getUserInputFromSerializedState: getUserInputFromSerializedState$a,getStartUserInput: getStartUserInput$a,getCorrectUserInput: getCorrectUserInput$4};
2028
+
2029
+ const getPromptJSON$e=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
2030
+
2031
+ class Group extends React__namespace.Component{componentDidMount(){this.forceUpdate();}getPromptJSON(){return getPromptJSON$e(this.rendererRef?.getPromptJSON())}getInputPaths(){return this.rendererRef?.getInputPaths()??[]}focus(){return this.rendererRef?.focus()??false}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:(newFocus,oldFocus)=>{if(oldFocus){this.props.onBlur(oldFocus);}if(newFocus){this.props.onFocus(newFocus);}}};return jsxRuntimeExports.jsx("div",{className:classNames__default.default({"perseus-group":true}),children:jsxRuntimeExports.jsx(Renderer,{userInput:this.props.userInput,handleUserInput:(widgetId,userInput)=>{this.props.handleUserInput({...this.props.userInput,[widgetId]:userInput});},content:this.props.content,widgets:this.props.widgets,images:this.props.images,ref:ref=>this.rendererRef=ref,apiOptions:apiOptions,findExternalWidgets:this.props.findWidgets,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,linterContext:this.props.linterContext,strings:this.context.strings})})}constructor(...args){super(...args),this.getSerializedState=()=>{return this.rendererRef?.getSerializedState()},this.focusInputPath=path=>{this.rendererRef?.focusPath(path);},this.blurInputPath=path=>{this.rendererRef?.blurPath(path);};}}Group.contextType=PerseusI18nContext;Group.defaultProps={content:"",widgets:{},images:{},linterContext:PerseusLinter.linterContextDefault};function getStartUserInput$9(options,problemNum){return sharedInitializeUserInput(options.widgets,problemNum)}function getUserInputFromSerializedState$9(serializedState,widgetOptions){return deriveUserInputFromSerializedState(serializedState,widgetOptions.widgets)}var Group$1 = {name:"group",displayName:"Group (SAT only)",widget:Group,hidden:true,isLintable:true,getStartUserInput: getStartUserInput$9,getUserInputFromSerializedState: getUserInputFromSerializedState$9};
2032
+
2033
+ const getPromptJSON$d=()=>{return getUnsupportedPromptJSON("iframe")};
2034
+
2035
+ const{updateQueryString}=Util;class Iframe extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$d()}getSerializedState(){const{userInput:_,alignment:__,...rest}=this.props;return rest}render(){const style={width:String(this.props.width),height:String(this.props.height)};const{InitialRequestUrl}=getDependencies();Object.entries(style).forEach(([key,value])=>{if(!value.endsWith("%")&&!value.endsWith("px")){style[key]=value+"px";}});let url=this.props.url;if(url&&url.length&&url.indexOf("http")!==0){url="https://www.khanacademy.org/computer-programming/program/"+url+"/embedded?buttons=no&embed=yes&editor=no&author=no";url=updateQueryString(url,"width",`${this.props.width}`);url=updateQueryString(url,"height",`${this.props.height}`);url=updateQueryString(url,"origin",InitialRequestUrl.origin);}if(this.context?.locale&&url?.includes("khanacademy.org")){url=updateQueryString(url,"lang",this.context.locale);}if(this.props.settings){const settings={};this.props.settings.forEach(setting=>{if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString(url,"settings",JSON.stringify(settings));}let sandboxProperties="allow-same-origin allow-scripts";sandboxProperties+=" allow-top-navigation";return jsxRuntimeExports.jsx("iframe",{title:this.context.strings.embeddedContent,sandbox:sandboxProperties,style:style,src:url,allowFullScreen:this.props.allowFullScreen})}constructor(...args){super(...args),this.handleMessageEvent=e=>{let data={};try{data=JSON.parse(e.originalEvent.data);}catch{return}if(data.testsPassed===undefined){return}const status=data.testsPassed?"correct":"incorrect";this.props.handleUserInput({status:status,message:data.message});};}}Iframe.contextType=PerseusI18nContext;Iframe.defaultProps={allowFullScreen:false,allowTopNavigation:false,userInput:{status:"incomplete",message:null}};function getUserInputFromSerializedState$8(serializedState){return {status:serializedState.status,message:serializedState.message}}function getStartUserInput$8(){return {status:"incomplete",message:null}}var Iframe$1 = {name:"iframe",displayName:"Iframe (deprecated)",widget:Iframe,hidden:true,getStartUserInput: getStartUserInput$8,getUserInputFromSerializedState: getUserInputFromSerializedState$8};
2036
+
2037
+ const getPromptJSON$c=widgetData=>{return {type:"image",options:{altText:widgetData.alt,title:widgetData.title,caption:widgetData.caption,imageUrl:widgetData.backgroundImage.url}}};
2038
+
2039
+ var styles$e = {"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"};
2040
+
2041
+ 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}})}
2042
+
2043
+ 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})};
2044
+
2045
+ 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$e.modalPanelContainer,children:[jsxRuntimeExports.jsx("div",{className:styles$e.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$e.modalDescriptionContainer}`,children:[imageIsGif&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(GifControlsButton,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),jsxRuntimeExports.jsx("div",{className:styles$e.spacerVertical})]}),caption&&jsxRuntimeExports.jsx("div",{id:captionId,className:styles$e.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}};
2046
+
2047
+ 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$e.modalTitleContainer}`,children:jsxRuntimeExports.jsx(Renderer,{content:titleText,apiOptions:props.apiOptions,linterContext:props.linterContext,strings:context.strings})});return jsxRuntimeExports.jsx("div",{className:`framework-perseus ${styles$e.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%"}};
2048
+
2049
+ 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}})};
2050
+
2051
+ 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$e.infoAreaContainer,children:[imageIsGif&&jsxRuntimeExports.jsx(GifControlsIcon,{isPlaying:isGifPlaying,onToggle:()=>setIsGifPlaying(!isGifPlaying)}),imageIsGif&&longDescription&&jsxRuntimeExports.jsx("div",{className:styles$e.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})})]})};
2052
+
2053
+ 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$e.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})]})};
2054
+
2055
+ const defaultBoxSize=400;const defaultRange=[0,10];const defaultBackgroundImage={url:null,width:0,height:0};class ImageWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$c(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,scale:1,labels:[],alt:"",longDescription:"",decorative:false,caption:"",linterContext:PerseusLinter.linterContextDefault};var Image$1 = {name:"image",displayName:"Image",widget:ImageWidget,isLintable:true};
2056
+
2057
+ const getPromptJSON$b=()=>{return getUnsupportedPromptJSON("interaction")};
2058
+
2059
+ const Label=Graphie.Label;const Line$1=Graphie.Line;const MovablePoint$1=Graphie.MovablePoint;const MovableLine=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$b()}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$1,{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$1.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$1,{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$1.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,{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$1,{coord:start,static:true,normalStyle:{stroke:"none",fill:"none"}}),jsxRuntimeExports.jsx(MovablePoint$1,{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};
2062
2060
 
2063
2061
  const bodyXsmallBold={fontFamily:"inherit",fontSize:15,fontWeight:"bold",lineHeight:"22px"};
2064
2062
 
@@ -2066,19 +2064,19 @@ const getPromptJSON$a=widgetData=>{const propMarkers=widgetData.markers.map(mark
2066
2064
 
2067
2065
  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
2066
 
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"}});
2067
+ 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
2068
 
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"}});
2069
+ 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
2070
 
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}});
2071
+ 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
2072
 
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"}});
2073
+ 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
2074
 
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"}});
2075
+ 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
2076
 
2079
2077
  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
2078
 
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"}});
2079
+ 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
2080
 
2083
2081
  const getPromptJSON$8=widgetData=>{return {type:"matrix",options:{height:widgetData.matrixBoardSize[0],width:widgetData.matrixBoardSize[1]},userInput:{answerRows:widgetData.userInput.answers}}};
2084
2082
 
@@ -2086,9 +2084,9 @@ const{assert: assert$2}=InteractiveUtil;const NORMAL_DIMENSIONS={INPUT_MARGIN:3,
2086
2084
 
2087
2085
  const getPromptJSON$7=()=>{return getUnsupportedPromptJSON("measurer")};
2088
2086
 
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};
2087
+ 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};
2090
2088
 
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"};
2089
+ 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
2090
 
2093
2091
  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
2092
 
@@ -2106,7 +2104,7 @@ class PlaceholderCard extends React__namespace.Component{render(){return jsxRunt
2106
2104
 
2107
2105
  const getPromptJSON$4=()=>{return getUnsupportedPromptJSON("phet-simulation")};
2108
2106
 
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};
2107
+ const MOBILE_APP_BOTTOM_BAR_HEIGHT=66;class PhetSimulation extends React__namespace.Component{async componentDidMount(){await this.updateSimState(this.props.url);}async componentDidUpdate(prevProps){if(prevProps.url!==this.props.url){await this.updateSimState(this.props.url);}}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
2108
 
2111
2109
  const getPromptJSON$3=()=>{return getUnsupportedPromptJSON("plotter")};
2112
2110
 
@@ -2114,7 +2112,7 @@ const plotterDefaults=perseusCore.CoreWidgetRegistry.getDefaultWidgetOptions("pl
2114
2112
 
2115
2113
  const getPromptJSON$2=()=>{return getUnsupportedPromptJSON("python-program")};
2116
2114
 
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};
2115
+ function getUrlFromProgramID(programID){return `/python-program/${programID}/embedded`}class PythonProgram extends React__namespace.Component{getPromptJSON(){return getPromptJSON$2()}render(){let url=getUrlFromProgramID(this.props.programID);url=this.props.dependencies.generateUrl({url,context:"python_program:program_url",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
2116
 
2119
2117
  const getPromptJSON$1=userInput=>{return {type:"sorter",userInput:{values:userInput.options,changed:userInput.changed}}};
2120
2118
 
@@ -2124,22 +2122,20 @@ const{assert}=InteractiveUtil;function getInputPath(row,column){return [""+row,"
2124
2122
 
2125
2123
  const getPromptJSON=()=>{return getUnsupportedPromptJSON("video")};
2126
2124
 
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"}});
2125
+ const IS_URL$1=/^https?:\/\//;const getYoutubeId=url=>{const regExp=/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;const match=url.match(regExp);if(match&&match[7].length===11){return match[7]}return "videoNotFound"};const VideoTranscriptLink=props=>{const{location}=props;const{useVideo}=useDependencies();const[id,kind]=IS_URL$1.test(location)?[getYoutubeId(location),"YOUTUBE_ID"]:[location,"READABLE_ID"];const result=useVideo(id,kind);const{strings}=usePerseusI18n();switch(result.status){case "loading":return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:strings.loading});case "success":{const video=result.data?.video;return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$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
2126
 
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};
2127
+ var styles$3 = {"perseusVideoWidget":"perseus_gxXDcWBe","perseusVideoFixedToResponsive":"perseus_5hjlD7xq"};
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,{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
2130
 
2131
2131
  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
2132
 
2133
2133
  const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
2134
2134
 
2135
- const libName="@khanacademy/perseus";const libVersion="78.0.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2135
+ const libName="@khanacademy/perseus";const libVersion="78.1.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
2136
2136
 
2137
2137
  const apiVersion={major:12,minor:0};
2138
2138
 
2139
- var allWidgets = [...basicWidgets,...extraWidgets];
2140
-
2141
- registerWidgets(allWidgets);const ItemVersion=getVersionVector();
2142
-
2143
2139
  class ArticleRenderer extends React__namespace.Component{componentDidMount(){this._currentFocus=null;}shouldComponentUpdate(nextProps){return nextProps!==this.props}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,isArticle:true};const classes=classNames__default.default({"framework-perseus":true,"perseus-article":true,[ClassNames.MOBILE]:apiOptions.isMobile});const sections=this._sections().map((section,sectionIndex)=>{return jsxRuntimeExports.jsx("div",{className:"clearfix",children:jsxRuntimeExports.jsx(UserInputManager,{widgets:section.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>React.createElement(Renderer,{...section,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,ref:elem=>{if(elem){this.sectionRenderers[sectionIndex]=elem;}},key:sectionIndex,keypadElement:this.props.keypadElement,apiOptions:{...apiOptions,onFocusChange:(newFocusPath,oldFocusPath)=>{this._handleFocusChange(newFocusPath&&[sectionIndex].concat(newFocusPath),oldFocusPath&&[sectionIndex].concat(oldFocusPath));}},linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"article"),legacyPerseusLint:this.props.legacyPerseusLint,strings:this.context.strings})})},sectionIndex)});return jsxRuntimeExports.jsx("div",{className:classes,children:jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:sections})})}constructor(props){super(props),this.sectionRenderers=[],this._handleFocusChange=(newFocusPath,oldFocusPath)=>{if(newFocusPath){this._setCurrentFocus(newFocusPath);}else {this._onRendererBlur(oldFocusPath);}},this._setCurrentFocus=newFocusPath=>{const{keypadElement,apiOptions}=this.props;const{isMobile}=apiOptions;const prevFocusPath=this._currentFocus;this._currentFocus=newFocusPath;let didFocusInput=false;let focusedInput;if(this._currentFocus){const[sectionIndex,...focusPath]=this._currentFocus;const inputPaths=this.sectionRenderers[sectionIndex].getInputPaths();didFocusInput=inputPaths.some(inputPath=>{return Util.inputPathsEqual(inputPath,focusPath)});focusedInput=this.sectionRenderers[sectionIndex].getDOMNodeForPath(focusPath);}const{onFocusChange}=this.props.apiOptions;if(onFocusChange){setTimeout(()=>{const keypadDomNode=keypadElement?.getDOMNode();const keypadHeight=keypadDomNode&&didFocusInput?keypadDomNode.getBoundingClientRect().height:0;onFocusChange(this._currentFocus,prevFocusPath,keypadHeight,didFocusInput?focusedInput:null);},0);}if(keypadElement&&isMobile){if(didFocusInput){keypadElement.activate();}else {keypadElement.dismiss();}}},this._onRendererBlur=blurPath=>{const blurringFocusPath=this._currentFocus;if(!Util.inputPathsEqual(blurPath,blurringFocusPath)){return}setTimeout(()=>{if(Util.inputPathsEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.blur=()=>{if(this._currentFocus){const[sectionIndex,...inputPath]=this._currentFocus;this.sectionRenderers[sectionIndex].blurPath(inputPath);}},this._sections=()=>{const sections=Array.isArray(this.props.json)?this.props.json:[this.props.json];if(getDependencies().JIPT.useJIPT){const paragraphs=[];for(const section of sections){JiptParagraphs.parseToArray(section.content).forEach(paragraph=>{paragraphs.push({...section,content:paragraph});});}return paragraphs}return sections};}}ArticleRenderer.contextType=PerseusI18nContext;ArticleRenderer.defaultProps={apiOptions:ApiOptions.defaults,linterContext:PerseusLinter__namespace.linterContextDefault};
2144
2140
 
2145
2141
  class HintRenderer extends React__namespace.Component{render(){if(this.props.hint.placeholder){return jsxRuntimeExports.jsx("span",{})}const{apiOptions,className,hint,lastHint,lastRendered,pos,totalHints}=this.props;const{isMobile}=apiOptions;const classNames=classNames__default.default("hint",!isMobile&&"perseus-hint-renderer",isMobile&&aphrodite.css(styles$2.newHint),isMobile&&lastRendered&&aphrodite.css(styles$2.lastRenderedNewHint),lastHint&&"last-hint",lastRendered&&"last-rendered",className);const rendererApiOptions={...apiOptions,customKeypad:false};return jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{className:classNames,tabIndex:"-1",children:[!apiOptions.isMobile&&jsxRuntimeExports.jsx("span",{className:"perseus-sr-only",children:this.context.strings.hintPos({pos:pos+1})}),!apiOptions.isMobile&&totalHints!=null&&pos!=null&&jsxRuntimeExports.jsx("span",{className:"perseus-hint-label",style:{display:"block",color:apiOptions.hintProgressColor},children:`${pos+1} / ${totalHints}`}),jsxRuntimeExports.jsx(UserInputManager,{widgets:hint.widgets,problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{ref:this.rendererRef,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,widgets:hint.widgets,content:hint.content||"",images:hint.images,apiOptions:rendererApiOptions,findExternalWidgets:this.props.findExternalWidgets,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"hint"),strings:this.context.strings})})]})})}constructor(...args){super(...args),this.rendererRef=React__namespace.createRef(),this.getSerializedState=()=>{return this.rendererRef.current?.getSerializedState()};}}HintRenderer.contextType=PerseusI18nContext;HintRenderer.defaultProps={linterContext:PerseusLinter__namespace.linterContextDefault};const styles$2=aphrodite.StyleSheet.create({newHint:{marginBottom:1.5*baseUnitPx,borderLeftColor:gray97,borderLeftStyle:"solid",borderLeftWidth:hintBorderWidth,[mediaQueries.lgOrSmaller]:{paddingLeft:baseUnitPx},[mediaQueries.smOrSmaller]:{paddingLeft:0},":focus":{outline:"none"}},lastRenderedNewHint:{marginBottom:0,borderLeftColor:kaGreen}});
@@ -2150,6 +2146,8 @@ const defaultContext={onRendered:isRendered=>{}};const context=React__namespace.
2150
2146
 
2151
2147
  class ServerItemRenderer extends React__namespace.Component{componentDidMount(){this._currentFocus=null;this._fullyRendered=false;this.maybeCallOnRendered();}componentDidUpdate(){this.maybeCallOnRendered();}componentWillUnmount(){if(this.blurTimeoutID!=null){clearTimeout(this.blurTimeoutID);this.blurTimeoutID=null;}}maybeCallOnRendered(){if(!this._fullyRendered){const assetsLoaded=Object.values(this.state.assetStatuses).every(Boolean);if(assetsLoaded){this._fullyRendered=true;this.props.onRendered(true);}}}_setCurrentFocus(newFocus){const{apiOptions:{isMobile,onFocusChange},keypadElement}=this.props;const prevFocus=this._currentFocus;this._currentFocus=newFocus;const inputPaths=this.getInputPaths();const didFocusInput=this._currentFocus&&inputPaths.some(inputPath=>{return Util.inputPathsEqual(inputPath,this._currentFocus)});if(onFocusChange!=null){setTimeout(()=>{const keypadDomNode=keypadElement?.getDOMNode();const keypadHeight=keypadDomNode&&didFocusInput?keypadDomNode.getBoundingClientRect().height:0;onFocusChange(this._currentFocus,prevFocus,keypadHeight,didFocusInput&&this.questionRenderer.getDOMNodeForPath(newFocus));},0);}if(keypadElement&&isMobile){if(didFocusInput){keypadElement.activate();}else {keypadElement.dismiss();}}}_onRendererBlur(blurPath){const blurringFocusPath=this._currentFocus;if(!___default.default.isEqual(blurPath,blurringFocusPath)){return}this.blurTimeoutID=setTimeout(()=>{if(___default.default.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}},0);}focusPath(path){return this.questionRenderer.focusPath(path)}blurPath(path){return this.questionRenderer.blurPath(path)}getDOMNodeForPath(path){return this.questionRenderer.getDOMNodeForPath(path)}getInputPaths(){const questionAreaInputPaths=this.questionRenderer.getInputPaths();return questionAreaInputPaths}focus(){return this.questionRenderer.focus()}blur(){if(this._currentFocus){this.blurPath(this._currentFocus);}}getNumHints(){return this.props.item.hints.length}getPromptJSON(){return this.questionRenderer.getPromptJSON()}getUserInput(){return this.userInput}getWidgetIds(){return this.questionRenderer.getWidgetIds()}getSerializedState(){return {question:this.questionRenderer.getSerializedState(),hints:this.hintsRenderer.getSerializedState()}}render(){const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,onFocusChange:this._handleFocusChange};const contextValue={assetStatuses:this.state.assetStatuses,setAssetStatus:this.setAssetStatus};const questionRenderer=jsxRuntimeExports.jsx(context$1.Provider,{value:contextValue,children:jsxRuntimeExports.jsx(UserInputManager,{widgets:this.props.item.question.widgets,problemNum:this.props.problemNum??0,children:({userInput,handleUserInput,initializeUserInput})=>{this.userInput=userInput;return jsxRuntimeExports.jsx(Renderer,{keypadElement:this.props.keypadElement,problemNum:this.props.problemNum,apiOptions:apiOptions,reviewMode:this.props.reviewMode,showSolutions:this.props.showSolutions,ref:elem=>{if(elem!=null){this.questionRenderer=elem;}},content:this.props.item.question.content,widgets:this.props.item.question.widgets,images:this.props.item.question.images,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"question"),strings:this.context.strings,...this.props.dependencies,userInput:userInput,handleUserInput:(id,userInput,widgetsEmpty)=>{handleUserInput(id,userInput,widgetsEmpty);},initializeUserInput:initializeUserInput})}})});const hintsRenderer=jsxRuntimeExports.jsx(HintsRenderer,{dependencies:this.props.dependencies,hints:this.props.item.hints,hintsVisible:this.props.hintsVisible,apiOptions:apiOptions,ref:elem=>this.hintsRenderer=elem,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"hints"),strings:this.context.strings});return jsxRuntimeExports.jsx(DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:questionRenderer}),jsxRuntimeExports.jsx("div",{className:apiOptions.isMobile?undefined:aphrodite.css(styles.hintsContainer),children:hintsRenderer})]})})}constructor(props){super(props),this._handleFocusChange=(newFocus,oldFocus)=>{if(newFocus!=null){this._setCurrentFocus(newFocus);}else {this._onRendererBlur(oldFocus);}},this.setAssetStatus=(assetKey,status)=>{const assetStatuses={...this.state.assetStatuses,[assetKey]:status};this.setState({assetStatuses});};this.state={assetStatuses:{}};this._fullyRendered=false;this.userInput={};}}ServerItemRenderer.contextType=PerseusI18nContext;ServerItemRenderer.defaultProps={apiOptions:{},linterContext:PerseusLinter__namespace.linterContextDefault,onRendered:isRendered=>{}};const styles=aphrodite.StyleSheet.create({hintsContainer:{marginLeft:50}});var serverItemRenderer = React__namespace.forwardRef(function ServerItemRendererWithRef(props,ref){return jsxRuntimeExports.jsx(context.Consumer,{children:({onRendered})=>jsxRuntimeExports.jsx(ServerItemRenderer,{...props,onRendered:onRendered,ref:ref})})});
2152
2148
 
2149
+ var allWidgets = [...basicWidgets,...extraWidgets];
2150
+
2153
2151
  function displaySigFigs(f,sigFigs,sigDecs,scientific){const s=""+f;let order=parseOrder(s);let mantissa=parseMantissa(s);let positive=parseSign(s);let add;let decAdd;let sigAdd;let zeroScientific=false;if(f==0||mantissa==""||mantissa=="0"){mantissa="";for(let i=0;i<sigFigs;i++){mantissa+="0";}order=sigFigs+sigDecs;if(sigDecs<0&&-sigDecs>=sigFigs){zeroScientific=true;}}else {decAdd=order-mantissa.length-sigDecs;sigAdd=sigFigs-mantissa.length;add=Math.min(sigAdd,decAdd);if(add<0){let rounded=round(mantissa,-add);if(rounded.length>mantissa.length+add){order++;if(decAdd>sigAdd){rounded=round(rounded,1);}}mantissa=rounded;}else if(add>0){for(let i=0;i<add;i++){mantissa+="0";}}if(mantissa==""||mantissa=="0"){mantissa="0";positive=true;order=1+sigDecs;if(order!=0){zeroScientific=true;}}}const useScientific=scientific||mantissa.length>20||order>4||order<-2||order-mantissa.length>0&&trailingZeros(mantissa)>0||zeroScientific;let returnVal="";if(!positive){returnVal+="-";}if(useScientific){returnVal+=mantissa.charAt(0);if(mantissa.length>1){returnVal+="."+mantissa.substring(1,mantissa.length);}if(order-1!=0){returnVal+=" x 10^"+(order-1);}}else {let wholePart="";let fractPart="";let needDot=true;if(order>0){if(mantissa.length>order){wholePart=mantissa.substring(0,order);fractPart=mantissa.substring(order,mantissa.length);}else {wholePart=mantissa;needDot=trailingZeros(mantissa)!=0;for(let i=0;i<order-mantissa.length;i++){wholePart+="0";}}}else {for(let i=0;i<-order;i++){fractPart+="0";}fractPart+=mantissa;}returnVal+=(wholePart==""?"0":wholePart)+(needDot?".":"")+fractPart;}return returnVal}function trailingZeros(mantissa){let zeros=0;for(let i=mantissa.length-1;i>=0;i--){const c=mantissa.charAt(i);if(c=="0"){zeros++;}else {return zeros}}return zeros}function parseSign(s){let beginning=true;let seenDot=false;let seenSomething=false;let zeros="";let all="";let pos=true;for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;beginning=false;}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}}else {if(seenSomething){zeros+=c;}}beginning=false;}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;beginning=false;}else if(c=="e"||c=="E"&&i+1<s.length){parseInt(s.substring(i+1,s.length));i=s.length;}else if(beginning&&(c=="+"||c=="-")){if(c=="-"){pos=!pos;}}}if(all==""){return true}return pos}function parseMantissa(s){let seenDot=false;let seenSomething=false;let zeros="";let leadZeros="";let all="";for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}else {leadZeros+=c;}}else {if(seenSomething){leadZeros+=c;zeros+=c;}else {leadZeros+=c;}}}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;}else if(c=="e"||c=="E"&&i+1<s.length){parseInt(s.substring(i+1,s.length));i=s.length;}else ;}if(all==""){return leadZeros}return all}function parseOrder(s){let seenDot=false;let seenSomething=false;let zeros="";let all="";let decPlaces=0;let totalDecs=0;for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;if(!seenDot){totalDecs++;decPlaces++;}}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}else {decPlaces--;}}else {totalDecs++;if(seenSomething){decPlaces++;zeros+=c;}}}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;}else if(c=="e"||c=="E"&&i+1<s.length){const raised=parseInt(s.substring(i+1,s.length));decPlaces+=raised;totalDecs+=raised;i=s.length;}else ;}if(all==""){return totalDecs}return decPlaces}function round(mantissa,digits){const last=mantissa.length-digits-1;if(last<0){return ""}if(last>=mantissa.length-1){return mantissa}const nextToLast=mantissa.charAt(last+1);const lastChar=mantissa.charAt(last);let roundUp=false;if(nextToLast>"5"){roundUp=true;}else if(nextToLast=="5"){for(let j=last+2;j<mantissa.length;j++){if(mantissa.charAt(j)!="0"){roundUp=true;}}if(lastChar%2==1){roundUp=true;}}let result="";for(let i=last;i>=0;i--){const c=mantissa.charAt(i);if(roundUp){let nextChar;if(c=="9"){nextChar="0";}else {switch(c){case "0":nextChar="1";break;case "1":nextChar="2";break;case "2":nextChar="3";break;case "3":nextChar="4";break;case "4":nextChar="5";break;case "5":nextChar="6";break;case "6":nextChar="7";break;case "7":nextChar="8";break;case "8":nextChar="9";break}roundUp=false;}result=nextChar+result;}else {result=c+result;}}if(roundUp){result="1"+result;}return result}
2154
2152
 
2155
2153
  const registerAllWidgetsForTesting=()=>{registerWidgets(allWidgets);replaceDeprecatedWidgets();};
@@ -2172,7 +2170,7 @@ var changeable = /*#__PURE__*/Object.freeze({
2172
2170
 
2173
2171
  const EditorJsonify={serialize:function(){return excludeDenylistKeys(this.props)}};
2174
2172
 
2175
- const GrapherUtil={DEFAULT_GRAPHER_PROPS,chooseType,defaultPlotProps,getEquationString: getEquationString$1,typeToButton};
2173
+ const GrapherUtil={DEFAULT_GRAPHER_PROPS,chooseType,defaultPlotProps,getEquationString,typeToButton};
2176
2174
 
2177
2175
  exports.ApiOptions = ApiOptions;
2178
2176
  exports.ArticleRenderer = ArticleRenderer;
@@ -2247,7 +2245,6 @@ exports.init = init;
2247
2245
  exports.interactiveSizes = interactiveSizes$1;
2248
2246
  exports.isWidgetIdInContent = isWidgetIdInContent;
2249
2247
  exports.isWrongAnswerSupported = isWrongAnswerSupported;
2250
- exports.itemVersion = ItemVersion;
2251
2248
  exports.libVersion = libVersion;
2252
2249
  exports.mathOnlyParser = mathOnlyParser;
2253
2250
  exports.parseDataFromJSONP = parseDataFromJSONP;