@khanacademy/perseus-editor 27.0.1 → 27.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/es/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { addLibraryVersionToPerseusDebug } from '@khanacademy/perseus-utils';
2
2
  import * as React from 'react';
3
3
  import React__default, { useId, createElement, useState, useRef, useEffect } from 'react';
4
- import { components, Widgets, iconTrash, excludeDenylistKeys, PerseusMarkdown, Util, preprocessTex, Log, ApiOptions, ClassNames, usePerseusI18n, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, Expression, interactiveSizes, GrapherWidget, GrapherUtil, containerSizeClass, getInteractiveBoxFromSizeClass, iconChevronDown, KhanColors, mathOnlyParser, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, bodyXsmallBold, MatrixWidget, makeSafeUrl, PlotterWidget, TableWidget, widgets } from '@khanacademy/perseus';
4
+ import { components, Widgets, iconTrash, excludeDenylistKeys, PerseusMarkdown, Util, preprocessTex, Log, ApiOptions, ClassNames, usePerseusI18n, UserInputManager, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify, Dependencies, Expression, interactiveSizes, GrapherWidget, GrapherUtil, containerSizeClass, getInteractiveBoxFromSizeClass, iconChevronDown, KhanColors, mathOnlyParser, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, bodyXsmallBold, MatrixWidget, makeSafeUrl, PlotterWidget, TableWidget, widgets } from '@khanacademy/perseus';
5
5
  export { widgets } from '@khanacademy/perseus';
6
6
  import { CoreWidgetRegistry, applyDefaultsToWidget, PerseusError, Errors, ItemExtras, categorizerLogic, csProgramLogic, definitionLogic, dropdownLogic, explanationLogic, expressionLogic, deriveExtraKeys, PerseusExpressionAnswerFormConsidered, freeResponseLogic, gradedGroupLogic, gradedGroupSetLogic, grapherLogic, GrapherUtil as GrapherUtil$1, groupLogic, iframeLogic, imageLogic, inputNumberLogic, interactionLogic, lockedFigureColors, lockedFigureFillStyles, interactiveGraphLogic, labelImageLogic, matcherLogic, matrixLogic, getMatrixSize, measurerLogic, numberLineLogic, numericInputLogic, ordererLogic, passageLogic, passageRefLogic, passageRefTargetLogic, phetSimulationLogic, plotterLogic, plotterPlotTypes, pythonProgramLogic, radioLogic, deriveNumCorrect, sorterLogic, tableLogic, videoLogic } from '@khanacademy/perseus-core';
7
7
  import _ from 'underscore';
@@ -34,8 +34,8 @@ import plusCircle from '@phosphor-icons/core/regular/plus-circle.svg';
34
34
  import trashIcon from '@phosphor-icons/core/regular/trash.svg';
35
35
  import { KhanMath, angles, vector, number } from '@khanacademy/kmath';
36
36
  import { inputNumberAnswerTypes } from '@khanacademy/perseus-score';
37
- import { SingleSelect, OptionItem, ActionMenu, ActionItem } from '@khanacademy/wonder-blocks-dropdown';
38
37
  import invariant from 'tiny-invariant';
38
+ import { SingleSelect, OptionItem, ActionMenu, ActionItem } from '@khanacademy/wonder-blocks-dropdown';
39
39
  import Banner from '@khanacademy/wonder-blocks-banner';
40
40
  import Pill from '@khanacademy/wonder-blocks-pill';
41
41
  import pencilCircle from '@phosphor-icons/core/regular/pencil-circle.svg';
@@ -57,10 +57,11 @@ import minusCircle from '@phosphor-icons/core/regular/minus-circle.svg';
57
57
  import arrowCounterClockwise from '@phosphor-icons/core/bold/arrow-counter-clockwise-bold.svg';
58
58
  import Link$1 from '@khanacademy/wonder-blocks-link';
59
59
  import plusIcon from '@phosphor-icons/core/bold/plus-bold.svg';
60
+ import xIcon from '@phosphor-icons/core/regular/x.svg';
60
61
  import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
61
62
  import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
62
63
 
63
- const libName="@khanacademy/perseus-editor";const libVersion="27.0.1";addLibraryVersionToPerseusDebug(libName,libVersion);
64
+ const libName="@khanacademy/perseus-editor";const libVersion="27.1.0";addLibraryVersionToPerseusDebug(libName,libVersion);
64
65
 
65
66
  var jsxRuntime = {exports: {}};
66
67
 
@@ -1412,7 +1413,7 @@ const SCREEN_SIZES={phone:{width:320,height:480,framedWidth:320},tablet:{width:7
1412
1413
 
1413
1414
  class JsonEditor extends React.Component{getInitialState(){return {currentValue:JSON.stringify(this.props.value,null,4),valid:true}}UNSAFE_componentWillReceiveProps(nextProps){const shouldReplaceContent=!this.state.valid||!_.isEqual(nextProps.value,JSON.parse(this.state.currentValue?this.state.currentValue:""));if(shouldReplaceContent){this.setState(this.getInitialState());}}handleKeyDown(e){if(e.key==="Tab"){const cursorPos=e.target.selectionStart;const v=e.target.value;const textBefore=v.substring(0,cursorPos);const textAfter=v.substring(cursorPos,v.length);e.target.value=textBefore+" "+textAfter;e.target.selectionStart=textBefore.length+4;e.target.selectionEnd=textBefore.length+4;e.preventDefault();this.handleChange(e);}}handleChange(e){const nextString=e.target.value;try{let json=JSON.parse(nextString);if(_.isString(json)){json=JSON.parse(json);}this.setState({currentValue:nextString,valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:nextString,valid:false});}}handleBlur(e){const nextString=e.target.value;try{let json=JSON.parse(nextString);if(_.isString(json)){json=JSON.parse(json);}this.setState({currentValue:JSON.stringify(json,null,4),valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}render(){const classes="perseus-json-editor "+(this.state.valid?"valid":"invalid");return jsxRuntimeExports.jsx("textarea",{className:classes,value:this.state.currentValue,onChange:this.handleChange,onKeyDown:this.handleKeyDown,onBlur:this.handleBlur})}constructor(props){super(props);this.state=this.getInitialState();this.handleBlur=this.handleBlur.bind(this);this.handleChange=this.handleChange.bind(this);this.handleKeyDown=this.handleKeyDown.bind(this);}}JsonEditor.defaultProps={value:{}};
1414
1415
 
1415
- const{InlineIcon: InlineIcon$7}=components;class SectionControlButton extends React.Component{render(){const{icon,onClick,title}=this.props;return jsxRuntimeExports.jsx(Clickable,{className:"section-control-button "+"simple-button "+"simple-button--small ",onClick:e=>{e.preventDefault();onClick();},role:"button",hideDefaultFocusRing:true,"aria-label":title,style:styles$U.button,children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(InlineIcon$7,{...icon})})}}const styles$U=StyleSheet.create({button:{backgroundColor:color.gold,margin:2,paddingRight:10,paddingLeft:10,paddingBottom:2}});
1416
+ const{InlineIcon: InlineIcon$7}=components;class SectionControlButton extends React.Component{render(){const{icon,onClick,title}=this.props;return jsxRuntimeExports.jsx(Clickable,{className:"section-control-button "+"simple-button "+"simple-button--small ",onClick:e=>{e.preventDefault();onClick();},role:"button",hideDefaultFocusRing:true,"aria-label":title,style:styles$S.button,children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(InlineIcon$7,{...icon})})}}const styles$S=StyleSheet.create({button:{backgroundColor:color.gold,margin:2,paddingRight:10,paddingLeft:10,paddingBottom:2}});
1416
1417
 
1417
1418
  const chemParse=function(tokens,stateMachine){let str="";let expectedLoc=tokens[tokens.length-1].loc.start;for(let i=tokens.length-1;i>=0;i--){if(tokens[i].loc.start>expectedLoc){str+=" ";expectedLoc=tokens[i].loc.start;}str+=tokens[i].text;expectedLoc+=tokens[i].text.length;}const tex=texify.go(mhchemParser.go(str,stateMachine));return tex};var mhchemParser={go:function(input,stateMachine){if(!input){return []}if(stateMachine===undefined){stateMachine="ce";}let state="0";const buffer={};buffer["parenthesisLevel"]=0;input=input.replace(/\n/g," ");input=input.replace(/[\u2212\u2013\u2014\u2010]/g,"-");input=input.replace(/[\u2026]/g,"...");let lastInput;let watchdog=10;const output=[];while(true){if(lastInput!==input){watchdog=10;lastInput=input;}else {watchdog--;}const machine=mhchemParser.stateMachines[stateMachine];const t=machine.transitions[state]||machine.transitions["*"];iterateTransitions:for(let i=0;i<t.length;i++){const matches=mhchemParser.patterns.match_(t[i].pattern,input);if(matches){const task=t[i].task;for(let iA=0;iA<task.action_.length;iA++){var o;if(machine.actions[task.action_[iA].type_]){o=machine.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else if(mhchemParser.actions[task.action_[iA].type_]){o=mhchemParser.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else {throw ["MhchemBugA","mhchem bug A. Please report. ("+task.action_[iA].type_+")"]}mhchemParser.concatArray(output,o);}state=task.nextState||state;if(input.length>0){if(!task.revisit){input=matches.remainder;}if(!task.toContinue){break iterateTransitions}}else {return output}}}if(watchdog<=0){throw ["MhchemBugU","mhchem bug U. Please report."]}}},concatArray:function(a,b){if(b){if(Array.isArray(b)){for(let iB=0;iB<b.length;iB++){a.push(b[iB]);}}else {a.push(b);}}},patterns:{patterns:{empty:/^$/,else:/^./,else2:/^./,space:/^\s/,"space A":/^\s(?=[A-Z\\$])/,space$:/^\s$/,"a-z":/^[a-z]/,x:/^x/,x$:/^x$/,i$:/^i$/,letters:/^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/,"\\greek":/^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/,"one lowercase latin letter $":/^(?:([a-z])(?:$|[^a-zA-Z]))$/,"$one lowercase latin letter$ $":/^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,"one lowercase greek letter $":/^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/,digits:/^[0-9]+/,"-9.,9":/^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,"-9.,9 no missing 0":/^[+\-]?[0-9]+(?:[.,][0-9]+)?/,"(-)(9.,9)(e)(99)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"(-)(9)^(-9)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"state of aggregation $":function(input){const a=mhchemParser.patterns.findObserveGroups(input,"",/^\([a-z]{1,3}(?=[\),])/,")","");if(a&&a.remainder.match(/^($|[\s,;\)\]\}])/)){return a}const m=input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/);if(m){return {match_:m[0],remainder:input.substr(m[0].length)}}return null},"_{(state of aggregation)}$":/^_\{(\([a-z]{1,3}\))\}/,"{[(":/^(?:\\\{|\[|\()/,")]}":/^(?:\)|\]|\\\})/,", ":/^[,;]\s*/,",":/^[,;]/,".":/^[.]/,". ":/^([.\u22C5\u00B7\u2022])\s*/,"...":/^\.\.\.(?=$|[^.])/,"* ":/^([*])\s*/,"^{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^{","","","}")},"^($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"^","$","$","")},"^a":/^\^([0-9]+|[^\\_])/,"^\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"^\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","")},"^\\x":/^\^(\\[a-zA-Z]+)\s*/,"^(-1)":/^\^(-?\d+)/,"'":/^'/,"_{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_{","","","}")},"_($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"_","$","$","")},_9:/^_([+\-]?[0-9]+|[^\\])/,"_\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"_\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","")},"_\\x":/^_(\\[a-zA-Z]+)\s*/,"^_":/^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,"{}":/^\{\}/,"{...}":function(input){return mhchemParser.patterns.findObserveGroups(input,"","{","}","")},"{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"{","","","}")},"$...$":function(input){return mhchemParser.patterns.findObserveGroups(input,"","$","$","")},"${(...)}$":function(input){return mhchemParser.patterns.findObserveGroups(input,"${","","","}$")},"$(...)$":function(input){return mhchemParser.patterns.findObserveGroups(input,"$","","","$")},"=<>":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(input){return mhchemParser.patterns.findObserveGroups(input,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(input){let match;match=input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}const a=mhchemParser.patterns.findObserveGroups(input,"","$","$","");if(a){match=a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}}return null},amount2:function(input){return this["amount"](input)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(input){if(input.match(/^\([a-z]+\)$/)){return null}const match=input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}return null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(input,begExcl,begIncl,endIncl,endExcl,beg2Excl,beg2Incl,end2Incl,end2Excl,combine){const _match=function(input,pattern){if(typeof pattern==="string"){if(input.indexOf(pattern)!==0){return null}return pattern}const match=input.match(pattern);if(!match){return null}return match[0]};const _findObserveGroups=function(input,i,endChars){let braces=0;while(i<input.length){const a=input.charAt(i);const match=_match(input.substr(i),endChars);if(match!==null&&braces===0){return {endMatchBegin:i,endMatchEnd:i+match.length}}if(a==="{"){braces++;}else if(a==="}"){if(braces===0){throw ["ExtraCloseMissingOpen","Extra close brace or missing open brace"]}else {braces--;}}i++;}if(braces>0){return null}return null};let match=_match(input,begExcl);if(match===null){return null}input=input.substr(match.length);match=_match(input,begIncl);if(match===null){return null}const e=_findObserveGroups(input,match.length,endIncl||endExcl);if(e===null){return null}const match1=input.substring(0,endIncl?e.endMatchEnd:e.endMatchBegin);if(!(beg2Excl||beg2Incl)){return {match_:match1,remainder:input.substr(e.endMatchEnd)}}const group2=this.findObserveGroups(input.substr(e.endMatchEnd),beg2Excl,beg2Incl,end2Incl,end2Excl);if(group2===null){return null}const matchRet=[match1,group2.match_];return {match_:combine?matchRet.join(""):matchRet,remainder:group2.remainder}},match_:function(m,input){const pattern=mhchemParser.patterns.patterns[m];if(pattern===undefined){throw ["MhchemBugP","mhchem bug P. Please report. ("+m+")"]}else if(typeof pattern==="function"){return mhchemParser.patterns.patterns[m](input)}else {const match=input.match(pattern);if(match){let mm;if(match[2]){mm=[match[1],match[2]];}else if(match[1]){mm=match[1];}else {mm=match[0];}return {match_:mm,remainder:input.substr(match[0].length)}}return null}}},actions:{"a=":function(buffer,m){buffer.a=(buffer.a||"")+m;},"b=":function(buffer,m){buffer.b=(buffer.b||"")+m;},"p=":function(buffer,m){buffer.p=(buffer.p||"")+m;},"o=":function(buffer,m){buffer.o=(buffer.o||"")+m;},"q=":function(buffer,m){buffer.q=(buffer.q||"")+m;},"d=":function(buffer,m){buffer.d=(buffer.d||"")+m;},"rm=":function(buffer,m){buffer.rm=(buffer.rm||"")+m;},"text=":function(buffer,m){buffer.text_=(buffer.text_||"")+m;},insert:function(buffer,m,a){return {type_:a}},"insert+p1":function(buffer,m,a){return {type_:a,p1:m}},"insert+p1+p2":function(buffer,m,a){return {type_:a,p1:m[0],p2:m[1]}},copy:function(buffer,m){return m},rm:function(buffer,m){return {type_:"rm",p1:m||""}},text:function(buffer,m){return mhchemParser.go(m,"text")},"{text}":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"text"));ret.push("}");return ret},"tex-math":function(buffer,m){return mhchemParser.go(m,"tex-math")},"tex-math tight":function(buffer,m){return mhchemParser.go(m,"tex-math tight")},bond:function(buffer,m,k){return {type_:"bond",kind_:k||m}},"color0-output":function(buffer,m){return {type_:"color0",color:m[0]}},ce:function(buffer,m){return mhchemParser.go(m)},"1/2":function(buffer,m){const ret=[];if(m.match(/^[+\-]/)){ret.push(m.substr(0,1));m=m.substr(1);}const n=m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);n[1]=n[1].replace(/\$/g,"");ret.push({type_:"frac",p1:n[1],p2:n[2]});if(n[3]){n[3]=n[3].replace(/\$/g,"");ret.push({type_:"tex-math",p1:n[3]});}return ret},"9,9":function(buffer,m){return mhchemParser.go(m,"9,9")}},createTransitions:function(o){let pattern;let state;let stateArray;let i;const transitions={};for(pattern in o){for(state in o[pattern]){stateArray=state.split("|");o[pattern][state].stateArray=stateArray;for(i=0;i<stateArray.length;i++){transitions[stateArray[i]]=[];}}}for(pattern in o){for(state in o[pattern]){stateArray=o[pattern][state].stateArray||[];for(i=0;i<stateArray.length;i++){const p=o[pattern][state];if(p.action_){p.action_=[].concat(p.action_);for(let k=0;k<p.action_.length;k++){if(typeof p.action_[k]==="string"){p.action_[k]={type_:p.action_[k]};}}}else {p.action_=[];}const patternArray=pattern.split("|");for(let j=0;j<patternArray.length;j++){if(stateArray[i]==="*"){for(const t in transitions){transitions[t].push({pattern:patternArray[j],task:p});}}else {transitions[stateArray[i]].push({pattern:patternArray[j],task:p});}}}}}return transitions},stateMachines:{}};mhchemParser.stateMachines={ce:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},else:{"0|1|2":{action_:"beginsWithBond=false",revisit:true,toContinue:true}},oxidation$:{0:{action_:"oxidation-output"}},CMT:{r:{action_:"rdt=",nextState:"rt"},rd:{action_:"rqt=",nextState:"rdt"}},arrowUpDown:{"0|1|2|as":{action_:["sb=false","output","operator"],nextState:"1"}},uprightEntities:{"0|1|2":{action_:["o=","output"],nextState:"1"}},orbital:{"0|1|2|3":{action_:"o=",nextState:"o"}},"->":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:false},nextState:"2"},q:{action_:{type_:"- after o/d",option:false},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:true},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:true},as:{action_:["output","sb=true"],nextState:"1",revisit:true},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:true},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(buffer,m){let ret;if((buffer.d||"").match(/^[0-9]+$/)){const tmp=buffer.d;buffer.d=undefined;ret=this["output"](buffer);buffer.b=tmp;}else {ret=this["output"](buffer);}mhchemParser.actions["o="](buffer,m);return ret},"d= kv":function(buffer,m){buffer.d=m;buffer.dType="kv";},"charge or bond":function(buffer,m){if(buffer["beginsWithBond"]){const ret=[];mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));return ret}buffer.d=m;},"- after o/d":function(buffer,m,isAfterD){let c1=mhchemParser.patterns.match_("orbital",buffer.o||"");const c2=mhchemParser.patterns.match_("one lowercase greek letter $",buffer.o||"");const c3=mhchemParser.patterns.match_("one lowercase latin letter $",buffer.o||"");const c4=mhchemParser.patterns.match_("$one lowercase latin letter$ $",buffer.o||"");const hyphenFollows=m==="-"&&(c1&&c1.remainder===""||c2||c3||c4);if(hyphenFollows&&!buffer.a&&!buffer.b&&!buffer.p&&!buffer.d&&!buffer.q&&!c1&&c3){buffer.o="$"+buffer.o+"$";}const ret=[];if(hyphenFollows){mhchemParser.concatArray(ret,this["output"](buffer));ret.push({type_:"hyphen"});}else {c1=mhchemParser.patterns.match_("digits",buffer.d||"");if(isAfterD&&c1&&c1.remainder===""){mhchemParser.concatArray(ret,mhchemParser.actions["d="](buffer,m));mhchemParser.concatArray(ret,this["output"](buffer));}else {mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));}}return ret},"a to o":function(buffer){buffer.o=buffer.a;buffer.a=undefined;},"sb=true":function(buffer){buffer.sb=true;},"sb=false":function(buffer){buffer.sb=false;},"beginsWithBond=true":function(buffer){buffer["beginsWithBond"]=true;},"beginsWithBond=false":function(buffer){buffer["beginsWithBond"]=false;},"parenthesisLevel++":function(buffer){buffer["parenthesisLevel"]++;},"parenthesisLevel--":function(buffer){buffer["parenthesisLevel"]--;},"state of aggregation":function(buffer,m){return {type_:"state of aggregation",p1:mhchemParser.go(m,"o")}},comma:function(buffer,m){const a=m.replace(/\s*$/,"");const withSpace=a!==m;if(withSpace&&buffer["parenthesisLevel"]===0){return {type_:"comma enumeration L",p1:a}}return {type_:"comma enumeration M",p1:a}},output:function(buffer,m,entityFollows){let ret;if(!buffer.r){ret=[];if(!buffer.a&&!buffer.b&&!buffer.p&&!buffer.o&&!buffer.q&&!buffer.d&&!entityFollows);else {if(buffer.sb){ret.push({type_:"entitySkip"});}if(!buffer.o&&!buffer.q&&!buffer.d&&!buffer.b&&!buffer.p&&entityFollows!==2){buffer.o=buffer.a;buffer.a=undefined;}else if(!buffer.o&&!buffer.q&&!buffer.d&&(buffer.b||buffer.p)){buffer.o=buffer.a;buffer.d=buffer.b;buffer.q=buffer.p;buffer.a=buffer.b=buffer.p=undefined;}else {if(buffer.o&&buffer.dType==="kv"&&mhchemParser.patterns.match_("d-oxidation$",buffer.d||"")){buffer.dType="oxidation";}else if(buffer.o&&buffer.dType==="kv"&&!buffer.q){buffer.dType=undefined;}}ret.push({type_:"chemfive",a:mhchemParser.go(buffer.a,"a"),b:mhchemParser.go(buffer.b,"bd"),p:mhchemParser.go(buffer.p,"pq"),o:mhchemParser.go(buffer.o,"o"),q:mhchemParser.go(buffer.q,"pq"),d:mhchemParser.go(buffer.d,buffer.dType==="oxidation"?"oxidation":"bd"),dType:buffer.dType});}}else {let rd;if(buffer.rdt==="M"){rd=mhchemParser.go(buffer.rd,"tex-math");}else if(buffer.rdt==="T"){rd=[{type_:"text",p1:buffer.rd||""}];}else {rd=mhchemParser.go(buffer.rd);}let rq;if(buffer.rqt==="M"){rq=mhchemParser.go(buffer.rq,"tex-math");}else if(buffer.rqt==="T"){rq=[{type_:"text",p1:buffer.rq||""}];}else {rq=mhchemParser.go(buffer.rq);}ret={type_:"arrow",r:buffer.r,rd:rd,rq:rq};}for(const p in buffer){if(p!=="parenthesisLevel"&&p!=="beginsWithBond"){delete buffer[p];}}return ret},"oxidation-output":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"oxidation"));ret.push("}");return ret},"frac-output":function(buffer,m){return {type_:"frac-ce",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"overset-output":function(buffer,m){return {type_:"overset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underset-output":function(buffer,m){return {type_:"underset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underbrace-output":function(buffer,m){return {type_:"underbrace",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1])}},"r=":function(buffer,m){buffer.r=m;},"rdt=":function(buffer,m){buffer.rdt=m;},"rd=":function(buffer,m){buffer.rd=m;},"rqt=":function(buffer,m){buffer.rqt=m;},"rq=":function(buffer,m){buffer.rq=m;},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}}}},a:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(buffer){if(buffer.text_){const ret={type_:"text",p1:buffer.text_};for(const p in buffer){delete buffer[p];}return ret}}}},pq:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:true}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:true}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:true}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(buffer,m){return {type_:"state of aggregation subscript",p1:mhchemParser.go(m,"o")}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"pq")}}}},bd:{transitions:mhchemParser.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:true}},formula$:{0:{nextState:"f",revisit:true}},else:{0:{nextState:"!f",revisit:true}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"bd")}}}},oxidation:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(buffer,m){return {type_:"roman numeral",p1:m||""}}}},"tex-math":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"tex-math tight":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(buffer,m){buffer.o=(buffer.o||"")+"{"+m+"}";},output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"9,9":{transitions:mhchemParser.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return {type_:"commaDecimal"}}}},pu:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}if(m[1]){mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));if(m[2]){if(m[2].match(/[,.]/)){mhchemParser.concatArray(ret,mhchemParser.go(m[2],"pu-9,9"));}else {ret.push(m[2]);}}m[3]=m[4]||m[3];if(m[3]){m[3]=m[3].trim();if(m[3]==="e"||m[3].substr(0,1)==="*"){ret.push({type_:"cdot"});}else {ret.push({type_:"times"});}}}if(m[3]){ret.push("10^{"+m[5]+"}");}return ret},"number^":function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));ret.push("^{"+m[2]+"}");return ret},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}},space:function(){return {type_:"pu-space-1"}},output:function(buffer){let ret;const md=mhchemParser.patterns.match_("{(...)}",buffer.d||"");if(md&&md.remainder===""){buffer.d=md.match_;}const mq=mhchemParser.patterns.match_("{(...)}",buffer.q||"");if(mq&&mq.remainder===""){buffer.q=mq.match_;}if(buffer.d){buffer.d=buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.d=buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");}if(buffer.q){buffer.q=buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.q=buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");const b5={d:mhchemParser.go(buffer.d,"pu"),q:mhchemParser.go(buffer.q,"pu")};if(buffer.o==="//"){ret={type_:"pu-frac",p1:b5.d,p2:b5.q};}else {ret=b5.d;if(b5.d.length>1||b5.q.length>1){ret.push({type_:" / "});}else {ret.push({type_:"/"});}mhchemParser.concatArray(ret,b5.q);}}else {ret=mhchemParser.go(buffer.d,"pu-2");}for(const p in buffer){delete buffer[p];}return ret}}},"pu-2":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return {type_:"tight cdot"}},"^(-1)":function(buffer,m){buffer.rm+="^{"+m+"}";},space:function(){return {type_:"pu-space-2"}},output:function(buffer){let ret=[];if(buffer.rm){const mrm=mhchemParser.patterns.match_("{(...)}",buffer.rm||"");if(mrm&&mrm.remainder===""){ret=mhchemParser.go(mrm.match_,"pu");}else {ret={type_:"rm",p1:buffer.rm};}}for(const p in buffer){delete buffer[p];}return ret}}},"pu-9,9":{transitions:mhchemParser.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return {type_:"commaDecimal"}},"output-0":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){let a=buffer.text_.length%3;if(a===0){a=3;}for(let i=buffer.text_.length-3;i>0;i-=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(0,a));ret.reverse();}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret},"output-o":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){const a=buffer.text_.length-3;for(var i=0;i<a;i+=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(i));}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret}}}};var texify={go:function(input,isInner){if(!input){return ""}let res="";let cee=false;for(let i=0;i<input.length;i++){const inputi=input[i];if(typeof inputi==="string"){res+=inputi;}else {res+=texify._go2(inputi);if(inputi.type_==="1st-level escape"){cee=true;}}}if(!isInner&&!cee&&res){res="{"+res+"}";}return res},_goInner:function(input){if(!input){return input}return texify.go(input,true)},_go2:function(buf){let res;switch(buf.type_){case "chemfive":res="";var b5={a:texify._goInner(buf.a),b:texify._goInner(buf.b),p:texify._goInner(buf.p),o:texify._goInner(buf.o),q:texify._goInner(buf.q),d:texify._goInner(buf.d)};if(b5.a){if(b5.a.match(/^[+\-]/)){b5.a="{"+b5.a+"}";}res+=b5.a+"\\,";}if(b5.b||b5.p){res+="{\\vphantom{X}}";res+="^{\\hphantom{"+(b5.b||"")+"}}_{\\hphantom{"+(b5.p||"")+"}}";res+="{\\vphantom{X}}";res+="^{\\smash[t]{\\vphantom{2}}\\mathllap{"+(b5.b||"")+"}}";res+="_{\\vphantom{2}\\mathllap{\\smash[t]{"+(b5.p||"")+"}}}";}if(b5.o){if(b5.o.match(/^[+\-]/)){b5.o="{"+b5.o+"}";}res+=b5.o;}if(buf.dType==="kv"){if(b5.d||b5.q){res+="{\\vphantom{X}}";}if(b5.d){res+="^{"+b5.d+"}";}if(b5.q){res+="_{\\smash[t]{"+b5.q+"}}";}}else if(buf.dType==="oxidation"){if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}}else {if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}}break;case "rm":res="\\mathrm{"+buf.p1+"}";break;case "text":if(buf.p1.match(/[\^_]/)){buf.p1=buf.p1.replace(" ","~").replace("-","\\text{-}");res="\\mathrm{"+buf.p1+"}";}else {res="\\text{"+buf.p1+"}";}break;case "roman numeral":res="\\mathrm{"+buf.p1+"}";break;case "state of aggregation":res="\\mskip2mu "+texify._goInner(buf.p1);break;case "state of aggregation subscript":res="\\mskip1mu "+texify._goInner(buf.p1);break;case "bond":res=texify._getBond(buf.kind_);if(!res){throw ["MhchemErrorBond","mhchem Error. Unknown bond type ("+buf.kind_+")"]}break;case "frac":var c="\\frac{"+buf.p1+"}{"+buf.p2+"}";res="\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}";break;case "pu-frac":var d="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";res="\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}";break;case "tex-math":res=buf.p1+" ";break;case "frac-ce":res="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "overset":res="\\overset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underset":res="\\underset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underbrace":res="\\underbrace{"+texify._goInner(buf.p1)+"}_{"+texify._goInner(buf.p2)+"}";break;case "color":res="{\\color{"+buf.color1+"}{"+texify._goInner(buf.color2)+"}}";break;case "color0":res="\\color{"+buf.color+"}";break;case "arrow":var b6={rd:texify._goInner(buf.rd),rq:texify._goInner(buf.rq)};var arrow="\\x"+texify._getArrow(buf.r);if(b6.rq){arrow+="[{"+b6.rq+"}]";}if(b6.rd){arrow+="{"+b6.rd+"}";}else {arrow+="{}";}res=arrow;break;case "operator":res=texify._getOperator(buf.kind_);break;case "1st-level escape":res=buf.p1+" ";break;case "space":res=" ";break;case "entitySkip":res="~";break;case "pu-space-1":res="~";break;case "pu-space-2":res="\\mkern3mu ";break;case "1000 separator":res="\\mkern2mu ";break;case "commaDecimal":res="{,}";break;case "comma enumeration L":res="{"+buf.p1+"}\\mkern6mu ";break;case "comma enumeration M":res="{"+buf.p1+"}\\mkern3mu ";break;case "comma enumeration S":res="{"+buf.p1+"}\\mkern1mu ";break;case "hyphen":res="\\text{-}";break;case "addition compound":res="\\,{\\cdot}\\,";break;case "electron dot":res="\\mkern1mu \\bullet\\mkern1mu ";break;case "KV x":res="{\\times}";break;case "prime":res="\\prime ";break;case "cdot":res="\\cdot ";break;case "tight cdot":res="\\mkern1mu{\\cdot}\\mkern1mu ";break;case "times":res="\\times ";break;case "circa":res="{\\sim}";break;case "^":res="uparrow";break;case "v":res="downarrow";break;case "ellipsis":res="\\ldots ";break;case "/":res="/";break;case " / ":res="\\,/\\,";break;default:throw ["MhchemBugT","mhchem bug T. Please report."]}return res},_getArrow:function(a){switch(a){case "->":return "rightarrow";case "→":return "rightarrow";case "⟶":return "rightarrow";case "<-":return "leftarrow";case "<->":return "leftrightarrow";case "<-->":return "rightleftarrows";case "<=>":return "rightleftharpoons";case "⇌":return "rightleftharpoons";case "<=>>":return "rightequilibrium";case "<<=>":return "leftequilibrium";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(a){switch(a){case "-":return "{-}";case "1":return "{-}";case "=":return "{=}";case "2":return "{=}";case "#":return "{\\equiv}";case "3":return "{\\equiv}";case "~":return "{\\tripledash}";case "~-":return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";case "~=":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "~--":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "-~-":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";case "...":return "{{\\cdot}{\\cdot}{\\cdot}}";case "....":return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case "->":return "{\\rightarrow}";case "<-":return "{\\leftarrow}";case "<":return "{<}";case ">":return "{>}";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(a){switch(a){case "+":return " {}+{} ";case "-":return " {}-{} ";case "=":return " {}={} ";case "<":return " {}<{} ";case ">":return " {}>{} ";case "<<":return " {}\\ll{} ";case ">>":return " {}\\gg{} ";case "\\pm":return " {}\\pm{} ";case "\\approx":return " {}\\approx{} ";case "$\\approx$":return " {}\\approx{} ";case "v":return " \\downarrow{} ";case "(v)":return " \\downarrow{} ";case "^":return " \\uparrow{} ";case "(^)":return " \\uparrow{} ";default:throw ["MhchemBugT","mhchem bug T. Please report."]}}};
1418
1419
 
@@ -1420,13 +1421,13 @@ katex.__defineMacro("\\ce",function(context){return chemParse(context.consumeArg
1420
1421
 
1421
1422
  class DragTarget extends React.Component{handleDrop(e){e.stopPropagation();e.preventDefault();this.setState({dragHover:false});this.props.onDrop(e);}handleDragEnd(){this.setState({dragHover:false});}handleDragOver(e){e.preventDefault();}handleDragLeave(){this.setState({dragHover:false});}handleDragEnter(e){this.setState({dragHover:this.props.shouldDragHighlight(e)});}render(){const opacity=this.state.dragHover?{opacity:.3}:{};const{component:Component,shouldDragHighlight,...forwardProps}=this.props;return jsxRuntimeExports.jsx(Component,{...forwardProps,style:Object.assign({},this.props.style,opacity),onDrop:this.handleDrop,onDragEnd:this.handleDragEnd,onDragOver:this.handleDragOver,onDragEnter:this.handleDragEnter,onDragLeave:this.handleDragLeave})}constructor(props){super(props);this.state={dragHover:false};this.handleDrop=this.handleDrop.bind(this);this.handleDragEnd=this.handleDragEnd.bind(this);this.handleDragOver=this.handleDragOver.bind(this);this.handleDragLeave=this.handleDragLeave.bind(this);this.handleDragEnter=this.handleDragEnter.bind(this);}}DragTarget.defaultProps={component:"div",shouldDragHighlight:()=>true};
1422
1423
 
1423
- function ToggleableCaret(props){const iconStyle=props.isExpanded?styles$T.expanded:styles$T.collapsed;return jsxRuntimeExports.jsx(PhosphorIcon,{icon:caretRight,style:iconStyle})}const styles$T=StyleSheet.create({collapsed:{transition:".15s"},expanded:{transform:"rotate(90deg)",transition:".15s"}});
1424
+ function ToggleableCaret(props){const iconStyle=props.isExpanded?styles$R.expanded:styles$R.collapsed;return jsxRuntimeExports.jsx(PhosphorIcon,{icon:caretRight,style:iconStyle})}const styles$R=StyleSheet.create({collapsed:{transition:".15s"},expanded:{transform:"rotate(90deg)",transition:".15s"}});
1424
1425
 
1425
1426
  const _upgradeWidgetInfo=props=>{const filteredProps=excludeDenylistKeys(props);return applyDefaultsToWidget(filteredProps)};class WidgetEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({widgetInfo:_upgradeWidgetInfo(nextProps)});if(nextProps.widgetIsOpen!=null&&nextProps.widgetIsOpen!==this.props.widgetIsOpen){this.setState({showWidget:nextProps.widgetIsOpen});}}render(){const widgetInfo=this.state.widgetInfo;const Ed=Widgets.getEditor(widgetInfo.type);let supportedAlignments;if(this.props.apiOptions.showAlignmentOptions){supportedAlignments=CoreWidgetRegistry.getSupportedAlignments(widgetInfo.type);}else {supportedAlignments=["default"];}const supportsStaticMode=Widgets.supportsStaticMode(widgetInfo.type);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-title "+(this.state.showWidget?"open":"closed"),children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-title-id",children:jsxRuntimeExports.jsxs(View,{style:{display:"flex",flexDirection:"row",alignItems:"center",gap:"0.25em"},onClick:this._toggleWidget,children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:this.state.showWidget}),jsxRuntimeExports.jsx("span",{children:this.props.id})]})}),supportsStaticMode&&jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Static",checked:!!widgetInfo.static,onChange:this._setStatic}),supportedAlignments.length>1&&jsxRuntimeExports.jsx("select",{className:"alignment",value:widgetInfo.alignment,onChange:this._handleAlignmentChange,children:supportedAlignments.map(alignment=>jsxRuntimeExports.jsx("option",{children:alignment},alignment))}),jsxRuntimeExports.jsx(SectionControlButton,{icon:iconTrash,onClick:()=>{this.props.onRemove();},title:"Remove image widget"})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-content "+(this.state.showWidget?"enter":"leave"),children:Ed&&jsxRuntimeExports.jsx(Ed,{ref:this.widget,onChange:this._handleWidgetChange,static:widgetInfo.static,apiOptions:this.props.apiOptions,...widgetInfo.options})})]})}constructor(props){super(props),this._toggleWidget=e=>{e.preventDefault();this.setState({showWidget:!this.state.showWidget});},this._handleWidgetChange=(newProps,cb,silent)=>{const newWidgetInfo={...this.state.widgetInfo,options:{...this.state.widgetInfo.options,...this.widget.current?.serialize()??{},...newProps}};this.props.onChange(newWidgetInfo,cb,silent);},this._setStatic=value=>{const newWidgetInfo={...this.state.widgetInfo,static:value};this.props.onChange(newWidgetInfo);},this._handleAlignmentChange=e=>{const newAlignment=e.currentTarget.value;const newWidgetInfo=Object.assign({},this.state.widgetInfo);newWidgetInfo.alignment=newAlignment;this.props.onChange(newWidgetInfo);},this.getSaveWarnings=()=>{const issuesFunc=this.widget.current?.getSaveWarnings;return issuesFunc?issuesFunc():[]},this.serialize=()=>{const widgetInfo=this.state.widgetInfo;return {type:widgetInfo.type,alignment:widgetInfo.alignment,static:widgetInfo.static,graded:widgetInfo.graded,options:this.widget.current.serialize(),version:widgetInfo.version}};this.state={showWidget:props.widgetIsOpen??true,widgetInfo:_upgradeWidgetInfo(props)};this.widget=React.createRef();}}function LabeledSwitch$1(props){const{label,...switchProps}=props;const id=useId();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("label",{htmlFor:id,children:label}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(Switch,{id:id,...switchProps})]})}
1426
1427
 
1427
1428
  class WidgetSelect extends React.Component{shouldComponentUpdate(){return false}render(){const widgets=Widgets.getPublicWidgets();const orderedWidgetNames=_.sortBy(_.keys(widgets),name=>{return widgets[name].displayName});const addWidgetString="Add a widget…";return jsxRuntimeExports.jsxs("select",{value:"",onChange:this.handleChange,"data-testid":"editor__widget-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:addWidgetString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),orderedWidgetNames.map(name=>{return jsxRuntimeExports.jsx("option",{value:name,children:widgets[name].displayName},name)})]})}constructor(...args){super(...args),this.handleChange=e=>{const widgetType=e.currentTarget.value;if(widgetType===""){return}if(this.props.onChange){this.props.onChange(widgetType);}};}}
1428
1429
 
1429
- class TexErrorView extends React.Component{render(){const{errorList}=this.props;const{showErrors}=this.state;return jsxRuntimeExports.jsxs(View,{style:styles$S.errorContainer,children:[jsxRuntimeExports.jsxs(View,{style:styles$S.title,onClick:this.handleToggleTexErrors,children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showErrors}),"  TeX Errors (",errorList.length,")"]}),showErrors&&jsxRuntimeExports.jsx(View,{style:styles$S.errorExplanation,children:"If your math doesn't display correctly, these errors might help you troubleshoot. Message #content-kitchen for help."}),showErrors&&errorList.map((e,index)=>jsxRuntimeExports.jsxs(View,{style:styles$S.error,children:[jsxRuntimeExports.jsx(View,{style:{color:"red"},children:e.math}),jsxRuntimeExports.jsx(View,{children:e.message})]},index))]})}constructor(...args){super(...args),this.state={showErrors:false},this.handleToggleTexErrors=e=>{this.setState({showErrors:!this.state.showErrors});};}}const styles$S=StyleSheet.create({title:{backgroundColor:"#eee",fontSize:"1.25em",padding:"4px 10px",cursor:"pointer",display:"flex",flexDirection:"row",alignItems:"center"},errorContainer:{border:"1px solid #ddd",borderTop:"none"},errorExplanation:{padding:"4px 10px",backgroundColor:"pink"},error:{padding:"4px 10px"}});
1430
+ class TexErrorView extends React.Component{render(){const{errorList}=this.props;const{showErrors}=this.state;return jsxRuntimeExports.jsxs(View,{style:styles$Q.errorContainer,children:[jsxRuntimeExports.jsxs(View,{style:styles$Q.title,onClick:this.handleToggleTexErrors,children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showErrors}),"  TeX Errors (",errorList.length,")"]}),showErrors&&jsxRuntimeExports.jsx(View,{style:styles$Q.errorExplanation,children:"If your math doesn't display correctly, these errors might help you troubleshoot. Message #content-kitchen for help."}),showErrors&&errorList.map((e,index)=>jsxRuntimeExports.jsxs(View,{style:styles$Q.error,children:[jsxRuntimeExports.jsx(View,{style:{color:"red"},children:e.math}),jsxRuntimeExports.jsx(View,{children:e.message})]},index))]})}constructor(...args){super(...args),this.state={showErrors:false},this.handleToggleTexErrors=e=>{this.setState({showErrors:!this.state.showErrors});};}}const styles$Q=StyleSheet.create({title:{backgroundColor:"#eee",fontSize:"1.25em",padding:"4px 10px",cursor:"pointer",display:"flex",flexDirection:"row",alignItems:"center"},errorContainer:{border:"1px solid #ddd",borderTop:"none"},errorExplanation:{padding:"4px 10px",backgroundColor:"pink"},error:{padding:"4px 10px"}});
1430
1431
 
1431
1432
  const widgetPlaceholder="[[☃ {id}]]";const widgetRegExp="(\\[\\[☃ {id}\\]\\])";const rWidgetSplit=new RegExp(widgetRegExp.replace("{id}","[a-z-]+ [0-9]+"),"g");const shortcutRegexp=/^\[\[([a-z-]+)$/;const ENDS_WITH_A_PARAGRAPH=/(?:\n{2,}|^\n*)$/;const TRAILING_NEWLINES=/(\n*)$/;const LEADING_NEWLINES=/^(\n*)/;const commafyInteger=n=>{let str=n.toString();if(str.length>=5){str=str.replace(/(\d)(?=(\d{3})+$)/g,"$1{,}");}return str};const makeEndWithAParagraphIfNecessary=content=>{if(!ENDS_WITH_A_PARAGRAPH.test(content)){const match=TRAILING_NEWLINES.exec(content);if(match){const newlines=match[1];return content+"\n\n".slice(0,2-newlines.length)}}return content};const makeStartWithAParagraphAlways=content=>{const match=LEADING_NEWLINES.exec(content);if(!match){return content}const newlines=match[1];return "\n\n".slice(0,2-newlines.length)+content};const IMAGE_REGEX$1=/!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;const allMatches=function(regex,str){const result=[];while(true){const match=regex.exec(str);if(!match){break}result.push(match);}return result};const imageUrlsFromContent=function(content){return allMatches(IMAGE_REGEX$1,content).map(capture=>capture[1])};class Editor extends React.Component{componentDidMount(){this.lastUserValue=null;this._sizeImages(this.props);$(this.textarea.current).on("copy cut",this._maybeCopyWidgets).on("paste",this._maybePasteWidgets);}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.content!==nextProps.content){this.setState({textAreaValue:nextProps.content});}}componentDidUpdate(prevProps){const textarea=this.textarea.current;if(this.lastUserValue!=null&&textarea){textarea.focus();textarea.value=this.lastUserValue;textarea.selectionStart=0;textarea.setSelectionRange(0,prevProps.content.length);if(document.execCommand("insertText",false,this.props.content)===false){textarea.value=this.props.content;}this.lastUserValue=null;}if(this.props.content!==prevProps.content){this._sizeImages(this.props);}}componentWillUnmount(){clearTimeout(this.deferredChange);}getWidgetEditor(id,type){if(!Widgets.getEditor(type)){return}return createElement(WidgetEditor,{...this.props.widgets[id],ref:id,id:id,key:id,onChange:this._handleWidgetEditorChange.bind(this,id),onRemove:this._handleWidgetEditorRemove.bind(this,id),apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}render(){let pieces;let widgets;let underlayPieces;let widgetsDropDown;let templatesDropDown;let widgetsAndTemplates;let wordCountDisplay;const katexErrorList=[];if(this.props.showWordCount){const numChars=PerseusMarkdown.characterCount(this.props.content);const numWords=Math.floor(numChars/6);wordCountDisplay=jsxRuntimeExports.jsx("span",{className:"perseus-editor-word-count",title:"~"+commafyInteger(numWords)+" words ("+commafyInteger(numChars)+" characters)",children:commafyInteger(numWords)});}if(this.props.widgetEnabled){pieces=Util.split(this.props.content,rWidgetSplit);widgets={};underlayPieces=[];for(let i=0;i<pieces.length;i++){if(i%2===0){underlayPieces.push(pieces[i]);const ast=PerseusMarkdown.parse(pieces[i]);PerseusMarkdown.traverseContent(ast,node=>{if(node.type==="math"||node.type==="blockMath"){const content=preprocessTex(node.content);try{katex.renderToString(content,{colorIsTextColor:true});}catch(e){katexErrorList.push({math:content,message:e.message});}}});}else {const match=Util.rWidgetParts.exec(pieces[i]);if(match!=null){const id=match[1];const type=match[2];const duplicate=id in widgets;widgets[id]=this.getWidgetEditor(id,type);const classes=(duplicate||!widgets[id]?"error ":"")+("");const key=duplicate?i:id;underlayPieces.push(jsxRuntimeExports.jsx("b",{className:classes,children:pieces[i]},key));}}}this.widgetIds=_.keys(widgets);widgetsDropDown=jsxRuntimeExports.jsx(WidgetSelect,{onChange:this._addWidget});const insertTemplateString="Insert template…";templatesDropDown=jsxRuntimeExports.jsxs("select",{onChange:this.addTemplate,"data-testid":"editor__template-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:insertTemplateString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"table",children:"Table"}),jsxRuntimeExports.jsx("option",{value:"titledTable",children:"Titled table"}),jsxRuntimeExports.jsx("option",{value:"alignment",children:"Aligned equations"}),jsxRuntimeExports.jsx("option",{value:"piecewise",children:"Piecewise function"}),Object.keys(this.props.additionalTemplates).length>0&&jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),Object.entries(this.props.additionalTemplates).map(([key])=>jsxRuntimeExports.jsx("option",{value:key,children:key},key)),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"allWidgets",children:"All widgets (for testing)"})]});if(!this.props.immutableWidgets){const widgetNodes=Object.values(widgets);widgetsAndTemplates=jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets-selectors",children:[widgetsDropDown,templatesDropDown,wordCountDisplay]}),widgetNodes]});wordCountDisplay=null;}}else {underlayPieces=[this.props.content];}underlayPieces.push(jsxRuntimeExports.jsx("br",{},"end"));const completeTextarea=[jsxRuntimeExports.jsx("div",{className:"perseus-textarea-underlay",ref:this.underlay,children:underlayPieces},"underlay"),jsxRuntimeExports.jsx("textarea",{ref:this.textarea,onChange:this.handleChange,onKeyDown:this._handleKeyDown,placeholder:this.props.placeholder,disabled:this.props.disabled,value:this.state.textAreaValue},"textarea")];let textareaWrapper;if(this.props.imageUploader){textareaWrapper=jsxRuntimeExports.jsx(DragTarget,{onDrop:this.handleDrop,className:"perseus-textarea-pair",children:completeTextarea});}else {textareaWrapper=jsxRuntimeExports.jsx("div",{className:"perseus-textarea-pair",children:completeTextarea});}const contentWithoutWidgets=this.props.content.replace(/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g,"");const noPrompt=contentWithoutWidgets.trim().length===0;const noWidgets=!/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g.test(this.props.content);const warningStyle={borderTop:"none",padding:4,backgroundColor:"pink"};return jsxRuntimeExports.jsxs("div",{className:"perseus-single-editor "+(this.props.className||""),children:[textareaWrapper,katexErrorList.length>0&&jsxRuntimeExports.jsx(TexErrorView,{errorList:katexErrorList}),this.props.warnNoPrompt&&noPrompt&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain a prompt"}),this.props.warnNoWidgets&&noWidgets&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain at least one widget"}),wordCountDisplay,widgetsAndTemplates]})}constructor(...args){super(...args),this.underlay=React.createRef(),this.textarea=React.createRef(),this.state={textAreaValue:this.props.content},this._handleWidgetEditorChange=(id,newWidgetInfo,cb,silent)=>{const widgets=Object.assign({},this.props.widgets);widgets[id]=Object.assign({},widgets[id],newWidgetInfo);this.props.onChange({widgets},cb,silent);},this._handleWidgetEditorRemove=id=>{if(!confirm("Are you sure you want to delete this item?")){return}const textarea=this.textarea.current;const re=new RegExp(widgetRegExp.replace("{id}",id),"gm");this.props.onChange({content:textarea?.value.replace(re,"")});},this._sizeImages=props=>{const imageUrls=imageUrlsFromContent(props.content);const images=_.pick(props.images,imageUrls);const newImageUrls=_.filter(imageUrls,url=>!images[url]);_.each(newImageUrls,url=>{Util.getImageSize(url,(width,height)=>{images[url]={width:width,height:height};props.onChange({images:_.clone(images)},null,true);});});},this.handleDrop=e=>{const{imageUploader}=this.props;let content=this.state.textAreaValue||"";const dataTransfer=e.dataTransfer;if(!dataTransfer||!imageUploader){return}const files=dataTransfer.files;if(files.length===0){const imageUrl=dataTransfer.getData("URL");if(imageUrl){const newContent=content+"\n\n![]("+imageUrl+")";this.lastUserValue=this.props.content;this.props.onChange({content:newContent});}return}const origContent=this.state.textAreaValue;_(files).chain().map(function(file){if(!file.type.match("image.*")){return null}const sentinel="☃ "+_.uniqueId("image_");content+="\n\n![]("+sentinel+")";return {file:file,sentinel:sentinel}}).reject(_.isNull).tap(()=>{this.lastUserValue=origContent;this.props.onChange({content:content});}).each(fileAndSentinel=>{imageUploader(fileAndSentinel.file,url=>{this.lastUserValue=origContent;this.props.onChange({content:this.state.textAreaValue.replace(fileAndSentinel.sentinel,url)});});});},this.handleChange=e=>{clearTimeout(this.deferredChange);this.setState({textAreaValue:e.currentTarget.value});this.deferredChange=setTimeout(()=>{if(this.state.textAreaValue!==this.props.content){this.props.onChange({content:this.state.textAreaValue});}},this.props.apiOptions.editorChangeDelay);},this._handleKeyDown=e=>{e.stopPropagation();if(e.key==="Tab"){const textarea=this.textarea.current;const word=Util.textarea.getWordBeforeCursor(textarea);const matches=word.string.toLowerCase().match(shortcutRegexp);if(matches!=null){const text=matches[1];const widgets=Widgets.getAllWidgetTypes();const matchingWidgets=widgets.filter(name=>{return name.substring(0,text.length)===text});if(matchingWidgets.length===1){const widgetType=matchingWidgets[0];this._addWidgetToContent(this.props.content,[word.pos.start,word.pos.end+1],widgetType);}e.preventDefault();}}},this._maybeCopyWidgets=e=>{const textarea=e.currentTarget;const selectedText=textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);const widgetNames=_.map(selectedText.match(rWidgetSplit),syntax=>{return Util.rWidgetParts.exec(syntax)[1]});const widgetData=_.pick(this.serialize().widgets,widgetNames);localStorage.perseusLastCopiedText=selectedText;localStorage.perseusLastCopiedWidgets=JSON.stringify(widgetData);Log.log(`Widgets copied: ${localStorage.perseusLastCopiedWidgets}`);},this._maybePasteWidgets=e=>{const widgetJSON=localStorage.perseusLastCopiedWidgets;const lastCopiedText=localStorage.perseusLastCopiedText;const textToBePasted=e.originalEvent.clipboardData.getData("text");if(widgetJSON&&lastCopiedText===textToBePasted){e.preventDefault();const widgetData=JSON.parse(widgetJSON);const safeWidgetMapping=this._safeWidgetNameMapping(widgetData);const safeWidgetData={};for(const[key,data]of Object.entries(widgetData)){safeWidgetData[safeWidgetMapping[key]]=data;}const newWidgets=_.extend(safeWidgetData,this.props.widgets);const safeText=lastCopiedText.replace(rWidgetSplit,syntax=>{const match=Util.rWidgetParts.exec(syntax);const completeWidget=match[0];const widget=match[1];return completeWidget.replace(widget,safeWidgetMapping[widget])});const textarea=e.currentTarget;const selectionStart=textarea.selectionStart;const newContent=this.state.textAreaValue.substr(0,selectionStart)+safeText+this.state.textAreaValue.substr(textarea.selectionEnd);this.lastUserValue=this.state.textAreaValue;this.props.onChange({content:newContent,widgets:newWidgets},()=>{const expectedCursorPosition=selectionStart+safeText.length;Util.textarea.moveCursor(textarea,expectedCursorPosition);});}},this._safeWidgetNameMapping=widgetData=>{const widgets=_.keys(widgetData).map(name=>name.split(" "));const widgetTypes=_.uniq(widgets.map(widget=>widget[0]));const existingWidgets=_.keys(this.props.widgets).map(name=>name.split(" "));const safeWidgetNums={};_.each(widgetTypes,type=>{safeWidgetNums[type]=_.chain(existingWidgets).filter(existingWidget=>existingWidget[0]===type).map(existingWidget=>+existingWidget[1]+1).max().value();safeWidgetNums[type]=Math.max(safeWidgetNums[type],1);});const safeWidgetMapping={};_.each(widgets,widget=>{const widgetName=widget.join(" ");const widgetType=widget[0];safeWidgetMapping[widgetName]=`${widgetType} ${safeWidgetNums[widgetType]}`;safeWidgetNums[widgetType]++;});return safeWidgetMapping},this._addWidgetToContent=(oldContent,cursorRange,widgetType)=>{const allWidgetIds=_.map(oldContent.match(rWidgetSplit),syntax=>{const match=Util.rWidgetParts.exec(syntax);const type=match[2];const num=+match[3];return [type,num]});const widgetNum=_.reduce(allWidgetIds,(currentNum,otherId)=>{const[otherType,otherNum]=otherId;if(otherType===widgetType){return Math.max(otherNum+1,currentNum)}return currentNum},1);const id=widgetType+" "+widgetNum;const widgetContent=widgetPlaceholder.replace("{id}",id);const isBlock=CoreWidgetRegistry.getDefaultAlignment(widgetType)==="block";const prelude=oldContent.slice(0,cursorRange[0]);const postlude=oldContent.slice(cursorRange[1]);const newPrelude=isBlock?makeEndWithAParagraphIfNecessary(prelude):prelude;const newPostlude=isBlock?makeStartWithAParagraphAlways(postlude):postlude;const newContent=newPrelude+widgetContent+newPostlude;const newWidgets={...this.props.widgets};newWidgets[id]={options:Widgets.getEditor(widgetType)?.defaultProps,type:widgetType,version:Widgets.getVersion(widgetType)};this.lastUserValue=this.props.content;this.props.onChange({content:newContent,widgets:newWidgets},()=>{if(!this.textarea.current){return}Util.textarea.moveCursor(this.textarea.current,newContent.length-postlude.length);});},this._addWidget=widgetType=>{const textarea=this.textarea.current;if(!textarea){return}this._addWidgetToContent(this.props.content,[textarea.selectionStart,textarea.selectionEnd],widgetType);textarea.focus();},this.addTemplate=e=>{const templateType=e.currentTarget.value;if(templateType===""){return}e.currentTarget.value="";let oldContent=this.props.content;oldContent=oldContent.replace(/\n*$/,"\n\n");let template;if(templateType==="table"){template="header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="titledTable"){template="|| **Table title** ||\n"+"header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="alignment"){template="$\\begin{align} \n"+"\\\\\\\\\n"+"\\end{align}$";}else if(templateType==="piecewise"){template="$f(x) = \\begin{cases}\n"+"7 & \\text{if }x=1 \\\\\n"+"f(x-1)+5 & \\text{if }x > 1\n"+"\\end{cases}$";}else if(templateType==="allWidgets"){template=Widgets.getAllWidgetTypes().map(type=>`[[${Util.snowman} ${type} 1]]`).join("\n\n");}else if(templateType in this.props.additionalTemplates){template=this.props.additionalTemplates[templateType];}else {throw new PerseusError("Invalid template type: "+templateType,Errors.InvalidInput,{metadata:{templateType}})}const newContent=oldContent+template;this.lastUserValue=this.props.content;this.props.onChange({content:newContent},this.focusAndMoveToEnd);},this.getSaveWarnings=()=>{const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));const warnings=_(widgetIds).chain().map(id=>{const issuesFunc=this.refs[id].getSaveWarnings;const issues=issuesFunc?issuesFunc():[];return _.map(issues,issue=>id+": "+issue)}).flatten(true).value();return warnings},this.focus=()=>{const textarea=this.textarea.current;if(textarea){textarea.focus();}},this.focusAndMoveToEnd=()=>{this.focus();const textarea=this.textarea.current;if(textarea){textarea.selectionStart=textarea.value.length;textarea.selectionEnd=textarea.value.length;}},this.serialize=options=>{const widgets={};const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));_.each(widgetIds,id=>{widgets[id]=this.refs[id].serialize();});if(options&&options.keepDeletedWidgets){_.chain(this.props.widgets).keys().reject(id=>_.contains(widgetIds,id)).each(id=>{widgets[id]=this.props.widgets[id];});}return {replace:this.props.replace,content:this.props.content,images:this.props.images,widgets:widgets}};}}Editor.defaultProps={content:"",placeholder:"",widgets:{},images:{},disabled:false,widgetEnabled:true,immutableWidgets:false,showWordCount:false,warnNoPrompt:false,warnNoWidgets:false,additionalTemplates:{}};
1432
1433
 
@@ -1456,15 +1457,15 @@ const rendererProps=PropTypes.shape({content:PropTypes.string,images:PropTypes.o
1456
1457
 
1457
1458
  const itemProps=PropTypes.shape({question:PropTypes.shape({}).isRequired,answerArea:PropTypes.shape({}).isRequired,hints:PropTypes.arrayOf(PropTypes.any).isRequired});class ItemDiff extends React.Component{render(){const{before,after}=this.props;const hintCount=Math.max(before.hints.length,after.hints.length);const question=jsxRuntimeExports.jsx(RendererDiff,{before:before.question,after:after.question,title:"Question",showAlignmentOptions:false,showSeparator:true});const extras=jsxRuntimeExports.jsx(WidgetDiff,{before:before.answerArea,after:after.answerArea,title:"Question extras"});const hints=_.times(hintCount,function(n){return jsxRuntimeExports.jsx(RendererDiff,{before:n<before.hints.length?before.hints[n]:undefined,after:n<after.hints.length?after.hints[n]:undefined,title:`Hint ${n+1}`,showAlignmentOptions:false,showSeparator:n<hintCount-1},n)});return jsxRuntimeExports.jsxs("div",{className:"framework-perseus",children:[question,extras,hints&&jsxRuntimeExports.jsx("div",{className:"diff-separator"}),hints]})}}ItemDiff.propTypes={after:itemProps.isRequired,before:itemProps.isRequired};
1458
1459
 
1459
- const{InfoTip: InfoTip$p,InlineIcon: InlineIcon$4}=components;class HintEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor "+this.props.className,children:[this.props.showTitle&&jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,apiOptions:this.props.apiOptions,widgets:this.props.widgets||undefined,content:this.props.content||undefined,images:this.props.images,replace:this.props.replace,placeholder:"Type your hint here...",imageUploader:this.props.imageUploader,onChange:this.props.onChange,widgetIsOpen:this.props.widgetIsOpen},this.props.itemId),jsxRuntimeExports.jsxs("div",{className:"hint-controls-container clearfix",children:[this.props.showMoveButtons&&jsxRuntimeExports.jsxs("span",{className:"reorder-hints",children:[jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isLast?"hidden":"",onClick:_.partial(this.props.onMove,1),children:jsxRuntimeExports.jsx(InlineIcon$4,{...iconCircleArrowDown})})," ",jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isFirst?"hidden":"",onClick:_.partial(this.props.onMove,-1),children:jsxRuntimeExports.jsx(InlineIcon$4,{...iconCircleArrowUp})})," ",this.props.isLast&&jsxRuntimeExports.jsx(InfoTip$p,{children:jsxRuntimeExports.jsx("p",{children:"The last hint is automatically bolded."})})]}),jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.replace,onChange:this.handleChange}),"Replace previous hint",this.props.showRemoveButton&&jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.props.onRemove,children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconTrash}),"Remove this hint"," "]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.handleChange=e=>{this.props.onChange({replace:e.target.checked});},this.focus=()=>{this.editor.current?.focus();},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)};}}HintEditor.defaultProps={className:"",content:"",replace:false,showMoveButtons:true,showTitle:true,showRemoveButton:true};class CombinedHintEditor extends React.Component{componentDidMount(){this.updatePreview();}componentDidUpdate(){this.updatePreview();}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";return jsxRuntimeExports.jsxs("div",{className:"perseus-combined-hint-editor "+"perseus-editor-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(HintEditor,{ref:this.editor,itemId:this.props.itemId,isFirst:this.props.isFirst,isLast:this.props.isLast,widgets:this.props.hint.widgets,content:this.props.hint.content,images:this.props.hint.images,replace:this.props.hint.replace,imageUploader:this.props.imageUploader,onChange:this.props.onChange,onRemove:this.props.onRemove,onMove:this.props.onMove,apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL})})})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.frame=React.createRef(),this.updatePreview=()=>{const shouldBold=this.props.isLast&&!/\*\*/.test(this.props.hint.content);this.frame.current?.sendNewData({type:"hint",data:{hint:this.props.hint,bold:shouldBold,pos:this.props.pos,apiOptions:this.props.apiOptions,linterContext:{contentType:"hint",highlightLint:this.props.highlightLint,paths:this.props.contentPaths}}});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)},this.focus=()=>{this.editor.current?.focus();};}}CombinedHintEditor.defaultProps={highlightLint:false};class CombinedHintsEditor extends React.Component{render(){const{itemId,hints}=this.props;const hintElems=_.map(hints,function(hint,i){return jsxRuntimeExports.jsx(CombinedHintEditor,{ref:"hintEditor"+i,isFirst:i===0,isLast:i+1===hints.length,itemId:itemId,hint:hint,pos:i,imageUploader:this.props.imageUploader,onChange:this.handleHintChange.bind(this,i),onRemove:this.handleHintRemove.bind(this,i),onMove:this.handleHintMove.bind(this,i),deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,highlightLint:this.props.highlightLint,previewURL:this.props.previewURL,contentPaths:[],widgetIsOpen:this.props.widgetIsOpen},"hintEditor"+i)},this);return jsxRuntimeExports.jsxs("div",{className:"perseus-hints-editor perseus-editor-table",children:[hintElems,jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"add-hint-container perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("button",{type:"button",className:"add-hint simple-button orange",onClick:this.addHint,children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconPlus})," Add a hint"]})})})]})}constructor(...args){super(...args),this.handleHintChange=(i,newProps,cb,silent)=>{const hints=[...this.props.hints];hints[i]=_.extend({},this.serializeHint(i,{keepDeletedWidgets:true}),newProps);this.props.onChange({hints:hints},cb,silent);},this.handleHintRemove=i=>{if(!confirm("Are you sure you want to delete this hint?")){return}const hints=[...this.props.hints];hints.splice(i,1);this.props.onChange({hints:hints});},this.handleHintMove=(i,dir)=>{const hints=[...this.props.hints];const hint=hints.splice(i,1)[0];hints.splice(i+dir,0,hint);this.props.onChange({hints:hints},()=>{this.refs["hintEditor"+(i+dir)].focus();});},this.addHint=()=>{const hint={content:"",images:{},widgets:{}};const hints=[...this.props.hints,hint];this.props.onChange({hints:hints},()=>{const i=hints.length-1;this.refs["hintEditor"+i].focus();});},this.getSaveWarnings=()=>{return _.chain(this.props.hints).map((hint,i)=>{return _.map(this.refs["hintEditor"+i].getSaveWarnings(),issue=>"Hint "+(i+1)+": "+issue)}).flatten(true).value()},this.serialize=options=>{return this.props.hints.map((hint,i)=>{return this.serializeHint(i,options)})},this.serializeHint=(index,options)=>{return this.refs["hintEditor"+index].serialize(options)};}}CombinedHintsEditor.HintEditor=HintEditor;CombinedHintsEditor.defaultProps={onChange:()=>{},hints:[],highlightLint:false};
1460
+ const{InfoTip: InfoTip$q,InlineIcon: InlineIcon$4}=components;class HintEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor "+this.props.className,children:[this.props.showTitle&&jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,apiOptions:this.props.apiOptions,widgets:this.props.widgets||undefined,content:this.props.content||undefined,images:this.props.images,replace:this.props.replace,placeholder:"Type your hint here...",imageUploader:this.props.imageUploader,onChange:this.props.onChange,widgetIsOpen:this.props.widgetIsOpen},this.props.itemId),jsxRuntimeExports.jsxs("div",{className:"hint-controls-container clearfix",children:[this.props.showMoveButtons&&jsxRuntimeExports.jsxs("span",{className:"reorder-hints",children:[jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isLast?"hidden":"",onClick:_.partial(this.props.onMove,1),children:jsxRuntimeExports.jsx(InlineIcon$4,{...iconCircleArrowDown})})," ",jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isFirst?"hidden":"",onClick:_.partial(this.props.onMove,-1),children:jsxRuntimeExports.jsx(InlineIcon$4,{...iconCircleArrowUp})})," ",this.props.isLast&&jsxRuntimeExports.jsx(InfoTip$q,{children:jsxRuntimeExports.jsx("p",{children:"The last hint is automatically bolded."})})]}),jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.replace,onChange:this.handleChange}),"Replace previous hint",this.props.showRemoveButton&&jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.props.onRemove,children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconTrash}),"Remove this hint"," "]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.handleChange=e=>{this.props.onChange({replace:e.target.checked});},this.focus=()=>{this.editor.current?.focus();},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)};}}HintEditor.defaultProps={className:"",content:"",replace:false,showMoveButtons:true,showTitle:true,showRemoveButton:true};class CombinedHintEditor extends React.Component{componentDidMount(){this.updatePreview();}componentDidUpdate(){this.updatePreview();}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";return jsxRuntimeExports.jsxs("div",{className:"perseus-combined-hint-editor "+"perseus-editor-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(HintEditor,{ref:this.editor,itemId:this.props.itemId,isFirst:this.props.isFirst,isLast:this.props.isLast,widgets:this.props.hint.widgets,content:this.props.hint.content,images:this.props.hint.images,replace:this.props.hint.replace,imageUploader:this.props.imageUploader,onChange:this.props.onChange,onRemove:this.props.onRemove,onMove:this.props.onMove,apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL})})})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.frame=React.createRef(),this.updatePreview=()=>{const shouldBold=this.props.isLast&&!/\*\*/.test(this.props.hint.content);this.frame.current?.sendNewData({type:"hint",data:{hint:this.props.hint,bold:shouldBold,pos:this.props.pos,apiOptions:this.props.apiOptions,linterContext:{contentType:"hint",highlightLint:this.props.highlightLint,paths:this.props.contentPaths}}});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)},this.focus=()=>{this.editor.current?.focus();};}}CombinedHintEditor.defaultProps={highlightLint:false};class CombinedHintsEditor extends React.Component{render(){const{itemId,hints}=this.props;const hintElems=_.map(hints,function(hint,i){return jsxRuntimeExports.jsx(CombinedHintEditor,{ref:"hintEditor"+i,isFirst:i===0,isLast:i+1===hints.length,itemId:itemId,hint:hint,pos:i,imageUploader:this.props.imageUploader,onChange:this.handleHintChange.bind(this,i),onRemove:this.handleHintRemove.bind(this,i),onMove:this.handleHintMove.bind(this,i),deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,highlightLint:this.props.highlightLint,previewURL:this.props.previewURL,contentPaths:[],widgetIsOpen:this.props.widgetIsOpen},"hintEditor"+i)},this);return jsxRuntimeExports.jsxs("div",{className:"perseus-hints-editor perseus-editor-table",children:[hintElems,jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"add-hint-container perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("button",{type:"button",className:"add-hint simple-button orange",onClick:this.addHint,children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconPlus})," Add a hint"]})})})]})}constructor(...args){super(...args),this.handleHintChange=(i,newProps,cb,silent)=>{const hints=[...this.props.hints];hints[i]=_.extend({},this.serializeHint(i,{keepDeletedWidgets:true}),newProps);this.props.onChange({hints:hints},cb,silent);},this.handleHintRemove=i=>{if(!confirm("Are you sure you want to delete this hint?")){return}const hints=[...this.props.hints];hints.splice(i,1);this.props.onChange({hints:hints});},this.handleHintMove=(i,dir)=>{const hints=[...this.props.hints];const hint=hints.splice(i,1)[0];hints.splice(i+dir,0,hint);this.props.onChange({hints:hints},()=>{this.refs["hintEditor"+(i+dir)].focus();});},this.addHint=()=>{const hint={content:"",images:{},widgets:{}};const hints=[...this.props.hints,hint];this.props.onChange({hints:hints},()=>{const i=hints.length-1;this.refs["hintEditor"+i].focus();});},this.getSaveWarnings=()=>{return _.chain(this.props.hints).map((hint,i)=>{return _.map(this.refs["hintEditor"+i].getSaveWarnings(),issue=>"Hint "+(i+1)+": "+issue)}).flatten(true).value()},this.serialize=options=>{return this.props.hints.map((hint,i)=>{return this.serializeHint(i,options)})},this.serializeHint=(index,options)=>{return this.refs["hintEditor"+index].serialize(options)};}}CombinedHintsEditor.HintEditor=HintEditor;CombinedHintsEditor.defaultProps={onChange:()=>{},hints:[],highlightLint:false};
1460
1461
 
1461
- const PerseusEditorAccordion=props=>{const{animated,children,header,expanded,containerStyle,panelStyle,onToggle}=props;return jsxRuntimeExports.jsx(View,{className:"perseus-editor-accordion",children:jsxRuntimeExports.jsx(AccordionSection,{animated:animated,expanded:expanded,onToggle:onToggle,style:[styles$R.container,containerStyle],headerStyle:styles$R.accordionHeader,header:header,children:jsxRuntimeExports.jsx(View,{style:[styles$R.accordionPanel,panelStyle],children:children})})})};const styles$R=StyleSheet.create({container:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8},accordionHeader:{padding:spacing.small_12,paddingInlineEnd:0,height:spacing.xxLarge_48},accordionPanel:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxxSmall_4,paddingLeft:spacing.small_12,paddingRight:spacing.small_12}});
1462
+ const PerseusEditorAccordion=props=>{const{animated,children,header,expanded,containerStyle,panelStyle,headerStyle,onToggle}=props;return jsxRuntimeExports.jsx(View,{className:"perseus-editor-accordion",children:jsxRuntimeExports.jsx(AccordionSection,{animated:animated,expanded:expanded,onToggle:onToggle,style:[styles$P.container,containerStyle],headerStyle:[styles$P.accordionHeader,headerStyle],header:header,children:jsxRuntimeExports.jsx(View,{style:[styles$P.accordionPanel,panelStyle],children:children})})})};const styles$P=StyleSheet.create({container:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8},accordionHeader:{padding:spacing.small_12,paddingInlineEnd:0,height:spacing.xxLarge_48},accordionPanel:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxxSmall_4,paddingLeft:spacing.small_12,paddingRight:spacing.small_12}});
1462
1463
 
1463
1464
  const IssueDetails=({issue})=>{const[expanded,setExpanded]=React.useState(false);const toggleVisibility=()=>setExpanded(!expanded);return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:expanded,onToggle:toggleVisibility,containerStyle:{backgroundColor:color.fadedGold8},panelStyle:{backgroundColor:"white"},header:jsxRuntimeExports.jsx(LabelLarge,{style:{textOverflow:"ellipsis",maxWidth:"100%",overflow:"hidden",whiteSpace:"nowrap"},children:`Warning: ${issue.id}`}),children:[jsxRuntimeExports.jsx(LabelSmall,{style:{fontWeight:"bold"},children:"Description:"}),jsxRuntimeExports.jsx("span",{children:issue.description}),jsxRuntimeExports.jsx("a",{href:issue.helpUrl,target:"_blank",rel:"noreferrer",children:issue.help}),jsxRuntimeExports.jsx(LabelSmall,{style:{marginTop:"1em",fontWeight:"bold"},children:"Impact:"}),jsxRuntimeExports.jsxs("span",{style:{fontWeight:"initial"},children:[" ",issue.impact]}),jsxRuntimeExports.jsx(LabelSmall,{style:{marginTop:"1em",fontWeight:"bold"},children:"Issue:"}),jsxRuntimeExports.jsx("span",{children:issue.message})]})};
1464
1465
 
1465
1466
  const IssuesPanel=({issues=[]})=>{const[showPanel,setShowPanel]=useState(false);const hasWarnings=issues.length>0;const issuesCount=`${issues.length} issue${issues.length===1?"":"s"}`;const icon=hasWarnings?iconWarning:iconPass;const iconColor=hasWarnings?color.gold:color.green;const togglePanel=()=>{if(hasWarnings){setShowPanel(!showPanel);}};return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-title",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-title-id",children:jsxRuntimeExports.jsxs(View,{style:{display:"flex",flexDirection:"row",alignItems:"center",gap:"0.25em"},onClick:togglePanel,children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showPanel}),jsxRuntimeExports.jsx("span",{children:"Issues"})]})}),jsxRuntimeExports.jsx(PhosphorIcon,{icon:icon,size:"medium",color:iconColor,testId:`issues-icon-${icon}`,style:{marginRight:"0.25em"}}),issuesCount]}),showPanel&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-panel",children:jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-content",children:issues.map(issue=>jsxRuntimeExports.jsx(IssueDetails,{issue:issue},issue.id))})})]})};
1466
1467
 
1467
- const{InfoTip: InfoTip$o}=components;class ItemExtrasEditor extends React.Component{shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}render(){return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",infoTip:"Use the calculator when completing difficult calculations is NOT the intent of the question. DON’T use the calculator when testing the student’s ability to complete different types of computations.",checked:this.props.calculator,onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState});}}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show financial calculator",infoTip:"This provides the student with the ability to view a financial calculator, e.g., for answering financial questions. Once checked, requires at least one of the three options below to be checked.",checked:this.shouldShowFinancialCalculatorOptions(),onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState,financialCalculatorTotalAmount:newCheckedState,financialCalculatorTimeToPayOff:newCheckedState});}}),this.shouldShowFinancialCalculatorOptions()&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include monthly payment",infoTip:"This provides the student with the ability to view a monthly payment calculator; e.g., given a loan amount, interest rate, and term, what is the monthly payment?",checked:this.props.financialCalculatorMonthlyPayment,onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include total amount",infoTip:"This provides the student with the ability to view a total amount calculator; e.g., given a monthly payment, interest rate, and term, what is the total amount to be paid?",checked:this.props.financialCalculatorTotalAmount,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTotalAmount:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include time-to-pay-off",infoTip:"This provides the student with the ability to view a time to pay off calculator; e.g., given a loan amount, interest rate, and monthly payment, how long will it take to pay off the loan?",checked:this.props.financialCalculatorTimeToPayOff,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTimeToPayOff:newCheckedState});},indent:true})]}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show periodic table",infoTip:"This provides the student with the ability to view a periodic table of the elements, e.g., for answering chemistry questions.",checked:this.props.periodicTable,onChange:newCheckedState=>{this.props.onChange({periodicTable:newCheckedState,periodicTableWithKey:false});}}),this.props.periodicTable&&jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include key/legend with periodic table",infoTip:"Include a key for HS courses; omit for AP chemistry.",checked:this.props.periodicTableWithKey,onChange:newCheckedState=>{this.props.onChange({periodicTableWithKey:newCheckedState});},indent:true})]})})}constructor(...args){super(...args),this.serialize=()=>{const data={...ItemExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}return data};}}ItemExtrasEditor.defaultProps={calculator:false,financialCalculatorMonthlyPayment:false,financialCalculatorTotalAmount:false,financialCalculatorTimeToPayOff:false,periodicTable:false,periodicTableWithKey:false};const ItemExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$Q.checkbox,props.indent?styles$Q.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip$o,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$Q=StyleSheet.create({indented:{marginInlineStart:spacing.large_24}});
1468
+ const{InfoTip: InfoTip$p}=components;class ItemExtrasEditor extends React.Component{shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}render(){return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",infoTip:"Use the calculator when completing difficult calculations is NOT the intent of the question. DON’T use the calculator when testing the student’s ability to complete different types of computations.",checked:this.props.calculator,onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState});}}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show financial calculator",infoTip:"This provides the student with the ability to view a financial calculator, e.g., for answering financial questions. Once checked, requires at least one of the three options below to be checked.",checked:this.shouldShowFinancialCalculatorOptions(),onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState,financialCalculatorTotalAmount:newCheckedState,financialCalculatorTimeToPayOff:newCheckedState});}}),this.shouldShowFinancialCalculatorOptions()&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include monthly payment",infoTip:"This provides the student with the ability to view a monthly payment calculator; e.g., given a loan amount, interest rate, and term, what is the monthly payment?",checked:this.props.financialCalculatorMonthlyPayment,onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include total amount",infoTip:"This provides the student with the ability to view a total amount calculator; e.g., given a monthly payment, interest rate, and term, what is the total amount to be paid?",checked:this.props.financialCalculatorTotalAmount,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTotalAmount:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include time-to-pay-off",infoTip:"This provides the student with the ability to view a time to pay off calculator; e.g., given a loan amount, interest rate, and monthly payment, how long will it take to pay off the loan?",checked:this.props.financialCalculatorTimeToPayOff,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTimeToPayOff:newCheckedState});},indent:true})]}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show periodic table",infoTip:"This provides the student with the ability to view a periodic table of the elements, e.g., for answering chemistry questions.",checked:this.props.periodicTable,onChange:newCheckedState=>{this.props.onChange({periodicTable:newCheckedState,periodicTableWithKey:false});}}),this.props.periodicTable&&jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include key/legend with periodic table",infoTip:"Include a key for HS courses; omit for AP chemistry.",checked:this.props.periodicTableWithKey,onChange:newCheckedState=>{this.props.onChange({periodicTableWithKey:newCheckedState});},indent:true})]})})}constructor(...args){super(...args),this.serialize=()=>{const data={...ItemExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}return data};}}ItemExtrasEditor.defaultProps={calculator:false,financialCalculatorMonthlyPayment:false,financialCalculatorTotalAmount:false,financialCalculatorTimeToPayOff:false,periodicTable:false,periodicTableWithKey:false};const ItemExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$O.checkbox,props.indent?styles$O.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip$p,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$O=StyleSheet.create({indented:{marginInlineStart:spacing.large_24}});
1468
1469
 
1469
1470
  const WARNINGS={inaccessibleWidget:(widgetType,widgetId)=>({id:`${widgetId} inaccessible`,description:`This ${widgetType} widget (${widgetId}) is inaccessible. Consider using an alternative to support all learners. Please check out the following documentation on compliant widget options.`,helpUrl:"https://khanacademy.atlassian.net/wiki/spaces/LC/pages/1909489691/Widget+Fundamentals",help:"Widget Fundamentals",impact:"medium",message:"Selecting inaccessible widgets for a practice item will result in this exercise being hidden from users with 'Hide visually dependant content' setting set to true. Please select another widget or create an alternative practice item."}),genericLinterWarning:(rule,message)=>({id:rule,description:message,help:"Learn more about best practices for authoring items",helpUrl:"https://docs.google.com/document/d/1N13f4sY-7EXWDwQ04ivA9vJBVvPPd60qjBT73B4NHuM/edit?tab=t.0",impact:"low",message:message})};
1470
1471
 
@@ -1472,42 +1473,42 @@ class ItemEditor extends React.Component{static getDerivedStateFromProps(props){
1472
1473
 
1473
1474
  const{HUD}=components;class EditorPage extends React.Component{componentDidMount(){this._isMounted=true;this.updateRenderer();}componentDidUpdate(){setTimeout(()=>{this.updateRenderer();});}componentWillUnmount(){this._isMounted=false;}updateRenderer(){const hasEditor=!this.props.developerMode||!this.props.jsonMode;if(!this._isMounted||!hasEditor){return}const touch=this.props.previewDevice==="phone"||this.props.previewDevice==="tablet";const deviceBasedApiOptions={...this.getApiOptions(),customKeypad:touch,isMobile:touch};this.itemEditor.current?.triggerPreviewUpdate({type:"question",data:_({item:this.serialize(),apiOptions:deviceBasedApiOptions,initialHintsVisible:0,device:this.props.previewDevice,linterContext:{contentType:"exercise",highlightLint:this.state.highlightLint,paths:this.props.contentPaths||[]},reviewMode:true,legacyPerseusLint:this.itemEditor.current?.getSaveWarnings()}).extend(_(this.props).pick("problemNum"))});}getApiOptions(){return {...ApiOptions.defaults,...this.props.apiOptions}}getSaveWarnings(){const issues1=this.itemEditor.current?.getSaveWarnings();const issues2=this.hintsEditor.current?.getSaveWarnings();return issues1.concat(issues2)}serialize(options){if(this.props.jsonMode){return this.state.json}return _.extend(this.itemEditor.current?.serialize(options),{hints:this.hintsEditor.current?.serialize(options)})}render(){let className="framework-perseus";const touch=this.props.previewDevice==="phone"||this.props.previewDevice==="tablet";const deviceBasedApiOptions={...this.getApiOptions(),customKeypad:touch,isMobile:touch};if(deviceBasedApiOptions.isMobile){className+=" "+ClassNames.MOBILE;}return jsxRuntimeExports.jsxs("div",{id:"perseus",className:className,children:[jsxRuntimeExports.jsxs("div",{style:{marginBottom:10},children:[this.props.developerMode&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Developer JSON Mode:"," ",jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.jsonMode,onChange:this.toggleJsonMode})]})," "]}),!this.props.jsonMode&&jsxRuntimeExports.jsx(ViewportResizer,{deviceType:this.props.previewDevice,onViewportSizeChanged:this.props.onPreviewDeviceChange}),!this.props.jsonMode&&jsxRuntimeExports.jsx(HUD,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})]}),this.props.developerMode&&this.props.jsonMode&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,value:this.state.json,onChange:this.changeJSON})}),(!this.props.developerMode||!this.props.jsonMode)&&jsxRuntimeExports.jsx(ItemEditor,{ref:this.itemEditor,itemId:this.props.itemId,question:this.props.question,answerArea:this.props.answerArea,imageUploader:this.props.imageUploader,onChange:this.handleChange,deviceType:this.props.previewDevice,widgetIsOpen:this.state.widgetsAreOpen,apiOptions:deviceBasedApiOptions,previewURL:this.props.previewURL,issues:this.props.issues,additionalTemplates:this.props.additionalTemplates}),(!this.props.developerMode||!this.props.jsonMode)&&jsxRuntimeExports.jsx(CombinedHintsEditor,{ref:this.hintsEditor,itemId:this.props.itemId,hints:this.props.hints,imageUploader:this.props.imageUploader,onChange:this.handleChange,deviceType:this.props.previewDevice,apiOptions:deviceBasedApiOptions,previewURL:this.props.previewURL,highlightLint:this.state.highlightLint,widgetIsOpen:this.state.widgetsAreOpen})]})}constructor(props){super(props),this.itemEditor=React.createRef(),this.hintsEditor=React.createRef(),this.toggleJsonMode=()=>{this.setState({json:this.serialize({keepDeletedWidgets:true})},()=>{this.props.onChange({jsonMode:!this.props.jsonMode});});},this.handleChange=(toChange,cb,silent)=>{const newProps=_(this.props).pick("question","hints","answerArea");_(newProps).extend(toChange);this.props.onChange(newProps,cb,silent);},this.changeJSON=newJson=>{this.setState({json:newJson});this.props.onChange(newJson);};this.state={json:_.pick(this.props,"question","answerArea","hints"),gradeMessage:"",wasAnswered:false,highlightLint:true,widgetsAreOpen:this.props.widgetsAreOpen??true};this._isMounted=false;}}EditorPage.defaultProps={developerMode:false,jsonMode:false,onChange:()=>{}};
1474
1475
 
1475
- function ContentPreview({question,apiOptions,seamless,linterContext,legacyPerseusLint,previewDevice}){const i18n=usePerseusI18n();const isMobile=previewDevice!=="desktop";const className=isMobile?"perseus-mobile":"";return jsxRuntimeExports.jsx(View,{className:`framework-perseus ${className}`,style:[styles$P.container,!seamless?styles$P.gutter:undefined],children:jsxRuntimeExports.jsx(StatefulKeypadContextProvider,{children:jsxRuntimeExports.jsx(KeypadContext.Consumer,{children:({setKeypadActive,keypadElement,setKeypadElement})=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Renderer,{strings:i18n.strings,apiOptions:{...apiOptions,isMobile},keypadElement:keypadElement,linterContext:linterContext,legacyPerseusLint:legacyPerseusLint,...question}),jsxRuntimeExports.jsx(MobileKeypad,{onAnalyticsEvent:()=>Promise.resolve(),onDismiss:()=>setKeypadActive(false),onElementMounted:setKeypadElement})]})})})})}const styles$P=StyleSheet.create({container:{padding:spacing.xxxSmall_4,containerType:"inline-size",containerName:"perseus-root"},gutter:{marginRight:lintGutterWidth}});
1476
+ function ContentPreview({question,apiOptions,seamless,linterContext,legacyPerseusLint,previewDevice}){const i18n=usePerseusI18n();const isMobile=previewDevice!=="desktop";const className=isMobile?"perseus-mobile":"";return jsxRuntimeExports.jsx(View,{className:`framework-perseus ${className}`,style:[styles$N.container,!seamless?styles$N.gutter:undefined],children:jsxRuntimeExports.jsx(StatefulKeypadContextProvider,{children:jsxRuntimeExports.jsx(KeypadContext.Consumer,{children:({setKeypadActive,keypadElement,setKeypadElement})=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(UserInputManager,{widgets:question?.widgets||{},problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{strings:i18n.strings,apiOptions:{...apiOptions,isMobile},keypadElement:keypadElement,linterContext:linterContext,legacyPerseusLint:legacyPerseusLint,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,...question})}),jsxRuntimeExports.jsx(MobileKeypad,{onAnalyticsEvent:()=>Promise.resolve(),onDismiss:()=>setKeypadActive(false),onElementMounted:setKeypadElement})]})})})})}const styles$N=StyleSheet.create({container:{padding:spacing.xxxSmall_4,containerType:"inline-size",containerName:"perseus-root"},gutter:{marginRight:lintGutterWidth}});
1476
1477
 
1477
1478
  const{TextListEditor: TextListEditor$4}=components;const Categorizer=Categorizer$1.widget;class CategorizerEditor extends React.Component{render(){const categorizerProps={items:this.props.items,categories:this.props.categories,userInput:{values:this.props.values},handleUserInput:userInput=>{this.props.onChange({values:userInput.values});},apiOptions:this.props.apiOptions,trackInteraction:function(){}};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Randomize item order",checked:this.props.randomizeItems,onChange:value=>{this.props.onChange({randomizeItems:value});}})}),"Categories:",jsxRuntimeExports.jsx(TextListEditor$4,{options:this.props.categories,onChange:cat=>{this.change("categories",cat);},layout:"horizontal"}),"Items:",jsxRuntimeExports.jsx(TextListEditor$4,{options:this.props.items,onChange:items=>{this.change({items:items,values:_.first(this.props.values,items.length)});},layout:"vertical"}),jsxRuntimeExports.jsx(Categorizer,{...categorizerProps})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CategorizerEditor.propTypes={...Changeable.propTypes,apiOptions:ApiOptions.propTypes,items:PropTypes.arrayOf(PropTypes.string),categories:PropTypes.arrayOf(PropTypes.string),values:PropTypes.arrayOf(PropTypes.number),randomizeItems:PropTypes.bool};CategorizerEditor.widgetName="categorizer";CategorizerEditor.defaultProps=categorizerLogic.defaultWidgetOptions;
1478
1479
 
1479
1480
  class BlurInput extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({value:nextProps.value});}focus(){this.input.current?.focus();}render(){return jsxRuntimeExports.jsx("input",{ref:this.input,className:this.props.className,style:this.props.style,type:"text",value:this.state.value,onChange:this.handleChange,onBlur:this.handleBlur})}constructor(props){super(props),this.input=React.createRef(),this.handleChange=e=>{this.setState({value:e.target.value});},this.handleBlur=e=>{this.props.onChange(e.target.value);};this.state={value:this.props.value};}}
1480
1481
 
1481
- const{InfoTip: InfoTip$n}=components;const DEFAULT_WIDTH=400;const DEFAULT_HEIGHT=400;let PairEditor$1 = class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{className:"pair-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Name:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:[" ","Value:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairEditor$1.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor$1,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairsEditor$1.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};const KA_PROGRAM_URL=/khanacademy\.org\/computer-programming\/[^\/]+\/(\d+)/;function isolateProgramID(programUrl){const match=KA_PROGRAM_URL.exec(programUrl);if(match){programUrl=match[1];}return programUrl}class CSProgramEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.programID,onChange:this._handleProgramIDChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Editor",checked:this.props.showEditor,onChange:value=>{this.props.onChange({showEditor:value});}}),jsxRuntimeExports.jsx(InfoTip$n,{children:'If you show the editor, you should use the "full-width" alignment to make room for the width of the editor.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Buttons",checked:this.props.showButtons,onChange:value=>{this.props.onChange({showButtons:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor$1,{name:"settings",pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip$n,{children:["Settings that you add here are available to the program as an object returned by ",jsxRuntimeExports.jsx("code",{children:"Program.settings()"})]})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this._handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this._handleProgramIDChange=programID=>{programID=isolateProgramID(programID);const{isDevServer,InitialRequestUrl}=Dependencies.getDependencies();const host=isDevServer?InitialRequestUrl.origin:"https://www.khanacademy.org";const baseUrl=`${host}/api/internal/scratchpads/${programID}`;$.getJSON(baseUrl).done(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});}).fail((jqxhr,textStatus,error)=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{textStatus,programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CSProgramEditor.propTypes={...Changeable.propTypes};CSProgramEditor.widgetName="cs-program";CSProgramEditor.defaultProps=csProgramLogic.defaultWidgetOptions;
1482
+ const{InfoTip: InfoTip$o}=components;const DEFAULT_WIDTH=400;const DEFAULT_HEIGHT=400;let PairEditor$1 = class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{className:"pair-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Name:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:[" ","Value:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairEditor$1.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor$1,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairsEditor$1.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};const KA_PROGRAM_URL=/khanacademy\.org\/computer-programming\/[^\/]+\/(\d+)/;function isolateProgramID(programUrl){const match=KA_PROGRAM_URL.exec(programUrl);if(match){programUrl=match[1];}return programUrl}class CSProgramEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.programID,onChange:this._handleProgramIDChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Editor",checked:this.props.showEditor,onChange:value=>{this.props.onChange({showEditor:value});}}),jsxRuntimeExports.jsx(InfoTip$o,{children:'If you show the editor, you should use the "full-width" alignment to make room for the width of the editor.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Buttons",checked:this.props.showButtons,onChange:value=>{this.props.onChange({showButtons:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor$1,{name:"settings",pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip$o,{children:["Settings that you add here are available to the program as an object returned by ",jsxRuntimeExports.jsx("code",{children:"Program.settings()"})]})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this._handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this._handleProgramIDChange=programID=>{programID=isolateProgramID(programID);const{isDevServer,InitialRequestUrl}=Dependencies.getDependencies();const host=isDevServer?InitialRequestUrl.origin:"https://www.khanacademy.org";const baseUrl=`${host}/api/internal/scratchpads/${programID}`;$.getJSON(baseUrl).done(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});}).fail((jqxhr,textStatus,error)=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{textStatus,programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CSProgramEditor.propTypes={...Changeable.propTypes};CSProgramEditor.widgetName="cs-program";CSProgramEditor.defaultProps=csProgramLogic.defaultWidgetOptions;
1482
1483
 
1483
1484
  const{TextInput: TextInput$7}=components;class DefinitionEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-definition-editor",children:[jsxRuntimeExports.jsx("a",{href:"https://docs.google.com/document/d/1udaPef4imOfTMhmLDlWq4SM0mxL0r3YHFZE-5J1uGfo",target:"_blank",rel:"noreferrer",children:"Definition style guide"}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Word to be defined:"," ",jsxRuntimeExports.jsx(TextInput$7,{value:this.props.togglePrompt,onChange:this.change("togglePrompt"),placeholder:"define me"})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.definition,widgetEnabled:false,placeholder:"definition goes here",onChange:props=>{const newProps={};if(_.has(props,"content")){newProps.definition=props.content;}this.change(newProps);}})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DefinitionEditor.propTypes={...Changeable.propTypes,togglePrompt:PropTypes.string,definition:PropTypes.string,apiOptions:PropTypes.any};DefinitionEditor.widgetName="definition";DefinitionEditor.defaultProps=definitionLogic.defaultWidgetOptions;
1484
1485
 
1485
1486
  class DeprecatedStandinEditor extends React.Component{serialize(){return EditorJsonify.serialize.call(this)}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("p",{children:"This widget has been deprecated and removed"}),jsxRuntimeExports.jsx("p",{children:"Learners will see a message and they will not be graded on this part. Please replace this widget with a supported one."})]})}}DeprecatedStandinEditor.widgetName="deprecated-standin";
1486
1487
 
1487
- const{InfoTip: InfoTip$m,InlineIcon: InlineIcon$3}=components;class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsxs("p",{children:["The drop down is useful for making inequalities in a custom format. We normally use the symbols ","<",","," ",">",', ≤, ≥ (in that order) which you can copy into the choices. When possible, use the "multiple choice" answer type instead.']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsxs("p",{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writing accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})," ",'If left blank, the value will default to "Select an answer".']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsx("p",{children:"This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."})})]}),jsxRuntimeExports.jsx("div",{className:"clearfix"}),jsxRuntimeExports.jsx(LabelMedium,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map(function(choice,i){const checkedClass=choice.correct?"correct":"incorrect";return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{ref:"radio"+i,type:"radio",name:dropdownGroupName,checked:choice.correct?"checked":"",onChange:this.onCorrectChange.bind(this,i),value:i}),jsxRuntimeExports.jsx("input",{type:"text",ref:"editor"+i,onChange:this.onContentChange.bind(this,i),className:checkedClass,value:choice.content}),jsxRuntimeExports.jsx("a",{href:"#",className:"simple-button orange","aria-label":"Delete choice",onClick:this.removeChoice.bind(this,i),children:jsxRuntimeExports.jsx("span",{className:"remove-choice",children:jsxRuntimeExports.jsx(InlineIcon$3,{...iconTrash})})})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsxs("a",{href:"#",className:"simple-button orange",onClick:this.addChoice,children:[jsxRuntimeExports.jsx(InlineIcon$3,{...iconPlus})," Add a choice"," "]})})]})}constructor(...args){super(...args),this.onVisibleLabelChange=visibleLabel=>{this.props.onChange({visibleLabel});},this.onAriaLabelChange=ariaLabel=>{this.props.onChange({ariaLabel});},this.onPlaceholderChange=placeholder=>{this.props.onChange({placeholder});},this.onCorrectChange=choiceIndex=>{const choices=_.map(this.props.choices,function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,e)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=e.target.value;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=e=>{e.preventDefault();const choices=this.props.choices;const blankChoice={content:"",correct:false};this.props.onChange({choices:choices.concat([blankChoice])},this.focus.bind(this,choices.length));},this.removeChoice=(choiceIndex,e)=>{e.preventDefault();const choices=_(this.props.choices).clone();choices.splice(choiceIndex,1);this.props.onChange({choices:choices});},this.focus=i=>{ReactDOM.findDOMNode(this.refs["editor"+i]).focus();return true},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DropdownEditor.propTypes={choices:PropTypes.arrayOf(PropTypes.shape({content:PropTypes.string,correct:PropTypes.bool})),placeholder:PropTypes.string};DropdownEditor.widgetName="dropdown";DropdownEditor.defaultProps=dropdownLogic.defaultWidgetOptions;
1488
+ const{InfoTip: InfoTip$n,InlineIcon: InlineIcon$3}=components;class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsxs("p",{children:["The drop down is useful for making inequalities in a custom format. We normally use the symbols ","<",","," ",">",', ≤, ≥ (in that order) which you can copy into the choices. When possible, use the "multiple choice" answer type instead.']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsxs("p",{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writing accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})," ",'If left blank, the value will default to "Select an answer".']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsx("p",{children:"This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."})})]}),jsxRuntimeExports.jsx("div",{className:"clearfix"}),jsxRuntimeExports.jsx(LabelMedium,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map(function(choice,i){const checkedClass=choice.correct?"correct":"incorrect";return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{ref:"radio"+i,type:"radio",name:dropdownGroupName,checked:choice.correct?"checked":"",onChange:this.onCorrectChange.bind(this,i),value:i}),jsxRuntimeExports.jsx("input",{type:"text",ref:"editor"+i,onChange:this.onContentChange.bind(this,i),className:checkedClass,value:choice.content}),jsxRuntimeExports.jsx("a",{href:"#",className:"simple-button orange","aria-label":"Delete choice",onClick:this.removeChoice.bind(this,i),children:jsxRuntimeExports.jsx("span",{className:"remove-choice",children:jsxRuntimeExports.jsx(InlineIcon$3,{...iconTrash})})})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsxs("a",{href:"#",className:"simple-button orange",onClick:this.addChoice,children:[jsxRuntimeExports.jsx(InlineIcon$3,{...iconPlus})," Add a choice"," "]})})]})}constructor(...args){super(...args),this.onVisibleLabelChange=visibleLabel=>{this.props.onChange({visibleLabel});},this.onAriaLabelChange=ariaLabel=>{this.props.onChange({ariaLabel});},this.onPlaceholderChange=placeholder=>{this.props.onChange({placeholder});},this.onCorrectChange=choiceIndex=>{const choices=_.map(this.props.choices,function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,e)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=e.target.value;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=e=>{e.preventDefault();const choices=this.props.choices;const blankChoice={content:"",correct:false};this.props.onChange({choices:choices.concat([blankChoice])},this.focus.bind(this,choices.length));},this.removeChoice=(choiceIndex,e)=>{e.preventDefault();const choices=_(this.props.choices).clone();choices.splice(choiceIndex,1);this.props.onChange({choices:choices});},this.focus=i=>{ReactDOM.findDOMNode(this.refs["editor"+i]).focus();return true},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DropdownEditor.propTypes={choices:PropTypes.arrayOf(PropTypes.shape({content:PropTypes.string,correct:PropTypes.bool})),placeholder:PropTypes.string};DropdownEditor.widgetName="dropdown";DropdownEditor.defaultProps=dropdownLogic.defaultWidgetOptions;
1488
1489
 
1489
1490
  const{TextInput: TextInput$6}=components;class ExplanationEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-explanation-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Prompt to show explanation:"," ",jsxRuntimeExports.jsx(TextInput$6,{value:this.props.showPrompt,onChange:this.change("showPrompt")})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Prompt to hide explanation:"," ",jsxRuntimeExports.jsx(TextInput$6,{value:this.props.hidePrompt,onChange:this.change("hidePrompt")})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.explanation,widgets:this.props.widgets,widgetEnabled:true,immutableWidgets:false,onChange:props=>{const newProps={};if(_.has(props,"content")){newProps.explanation=props.content;}if(_.has(props,"widgets")){newProps.widgets=props.widgets;}this.change(newProps);}})})]})}constructor(...args){super(...args),this.state={},this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}ExplanationEditor.propTypes={...Changeable.propTypes,showPrompt:PropTypes.string,hidePrompt:PropTypes.string,explanation:PropTypes.string,widgets:PropTypes.object,apiOptions:PropTypes.any};ExplanationEditor.widgetName="explanation";ExplanationEditor.defaultProps=explanationLogic.defaultWidgetOptions;
1490
1491
 
1491
- const{ButtonGroup: ButtonGroup$7,InfoTip: InfoTip$l}=components;const buttonSetsList=["basic","trig","prealgebra","logarithms","scientific","basic relations","advanced relations"];class ExpressionEditor extends React.Component{serialize(){const{answerForms,buttonSets,functions,times,visibleLabel,ariaLabel}=this.props;return {answerForms,buttonSets,functions,times,visibleLabel,ariaLabel,extraKeys:deriveExtraKeys(this.props)}}updateAnswerForm(index,answerFormProps){const answerForms=this.props.answerForms.slice();answerForms[index]=answerFormProps;const{extraKeys:_,...restProps}=this.props;const extraKeys=deriveExtraKeys({...restProps,answerForms});this.props.onChange({answerForms,extraKeys});}changeSimplify(index,simplify){const answerForm={...this.props.answerForms[index],simplify};this.updateAnswerForm(index,answerForm);}changeForm(index,form){const answerForm={...this.props.answerForms[index],form};this.updateAnswerForm(index,answerForm);}changeConsidered(index,considered){const answerForm={...this.props.answerForms[index],considered};this.updateAnswerForm(index,answerForm);}changeTimes(times){this.props.onChange({times:times});}render(){const answerOptions=this.props.answerForms.map((ans,index)=>{const expressionProps={times:this.props.times,functions:this.props.functions,buttonSets:this.props.buttonSets,buttonsVisible:"focused",userInput:ans.value,handleUserInput:input=>this.changeExpressionWidget(index,input),trackInteraction:()=>{},widgetId:this.props.widgetId+"-"+ans.key,visibleLabel:this.props.visibleLabel,ariaLabel:this.props.ariaLabel};return jsxRuntimeExports.jsx(AnswerOption,{considered:ans.considered,expressionProps:expressionProps,form:ans.form,simplify:ans.simplify,onDelete:()=>this.handleRemoveForm(index),onChangeSimplify:simplify=>this.changeSimplify(index,simplify),onChangeForm:form=>this.changeForm(index,form),onChangeConsidered:considered=>this.changeConsidered(index,considered)},ans.key)});const buttonSetChoices=buttonSetsList.map(name=>{const isBasic=name==="basic";const checked=this.props.buttonSets.includes(name)||isBasic;return jsxRuntimeExports.jsx(Checkbox$1,{label:name,checked:checked,disabled:isBasic,onChange:()=>this.handleButtonSet(name)},name)});buttonSetChoices.unshift(jsxRuntimeExports.jsx(Checkbox$1,{label:"show ÷ button",checked:this.props.buttonSets.includes("basic+div"),onChange:this.handleToggleDiv},"show ÷ button"));return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Global Options"}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Visible label",jsxRuntimeExports.jsx(InfoTip$l,{children:"Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."})]}),value:this.props.visibleLabel||"",onChange:this.handleVisibleLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Aria label",jsxRuntimeExports.jsxs(InfoTip$l,{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})]})]}),value:this.props.ariaLabel||"",onChange:this.handleAriaLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Function variables",jsxRuntimeExports.jsx(InfoTip$l,{children:'Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means "f of x" and not "f times x".'})]}),value:this.state.functionsInternal,onChange:this.handleFunctions})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Use × instead of ⋅ for multiplication",jsxRuntimeExports.jsx(InfoTip$l,{children:"For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."})]}),checked:this.props.times,onChange:newCheckedState=>{this.changeTimes(newCheckedState);}})}),jsxRuntimeExports.jsxs("div",{className:css(styles$O.paddedY),children:[jsxRuntimeExports.jsx(HeadingXSmall,{children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(HeadingSmall,{children:"Answers"}),jsxRuntimeExports.jsx(Caption,{style:styles$O.answersSubtitle,children:"student responses area matched against these from top to bottom"}),jsxRuntimeExports.jsx(View,{style:{gap:spacing.xSmall_8},children:answerOptions}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.newAnswer,children:"Add new answer"})]})}constructor(props){super(props),this.getSaveWarnings=()=>{const issues=[];if(this.props.answerForms.length===0){issues.push("No answers specified");}else {const hasCorrect=this.props.answerForms.some(form=>{return form.considered==="correct"});if(!hasCorrect){issues.push("No correct answer specified");}_(this.props.answerForms).each((form,ix)=>{if(this.props.value===""){issues.push(`Answer ${ix+1} is empty`);}else {const expression=KAS.parse(form.value,{functions:this.props.functions});if(!expression.parsed){issues.push(`Couldn't parse ${form.value}`);}else if(form.simplify&&!expression.expr.isSimplified()){issues.push(`${form.value} isn't simplified, but is required" +
1492
- " to be`);}}});}return issues},this.newAnswer=()=>{const answerForms=this.props.answerForms.slice();const newKey=crypto.randomUUID();const newAnswerForm={considered:"correct",form:false,key:`${newKey}`,simplify:false,value:""};answerForms.push(newAnswerForm);this.props.onChange({answerForms});},this.handleRemoveForm=i=>{const updatedAnswerForms=this.props.answerForms.slice();updatedAnswerForms.splice(i,1);this.props.onChange({answerForms:updatedAnswerForms});},this.handleButtonSet=changingName=>{const buttonSetNames=buttonSetsList;const buttonSets=buttonSetNames.filter(set=>{return this.props.buttonSets.includes(set)!==(set===changingName)});this.props.onChange({buttonSets});},this.handleToggleDiv=()=>{let keep;let remove;if(this.props.buttonSets.includes("basic+div")){keep="basic";remove="basic+div";}else {keep="basic+div";remove="basic";}const buttonSets=this.props.buttonSets.filter(set=>set!==remove).concat(keep);this.props.onChange({buttonSets});},this.handleTexInsert=str=>{this.refs.expression.insert(str);},this.handleFunctions=value=>{this.setState({functionsInternal:value});const newProps={};newProps.functions=value.split(/[ ,]+/).filter(isTruthy);this.props.onChange(newProps);},this.handleVisibleLabel=visibleLabel=>{this.props.onChange({visibleLabel});},this.handleAriaLabel=ariaLabel=>{this.props.onChange({ariaLabel});},this.changeExpressionWidget=(index,input)=>{const answerForm={...this.props.answerForms[index],value:input};this.updateAnswerForm(index,answerForm);};this.state={functionsInternal:this.props.functions.join(" ")};}}ExpressionEditor.widgetName="expression";ExpressionEditor.defaultProps=expressionLogic.defaultWidgetOptions;const findNextIn=function(arr,val){let ix=arr.indexOf(val);ix=(ix+1)%arr.length;return arr[ix]};class AnswerOption extends React.Component{render(){const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",style:styles$O.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$O.answerOption),children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,value:this.props.considered,selectedButtonStyle:consideredButtonStyles[this.props.considered],buttons:PerseusExpressionAnswerFormConsidered.map(c=>({value:c,content:c,title:`This answer will be considered ${c}`}))}),jsxRuntimeExports.jsx(Expression,{...this.props.expressionProps}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip$l,{children:"The student's answer must be in the same form. Commutativity and excess negative signs are ignored."})]}),checked:this.props.form,onChange:this.props.onChangeForm})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip$l,{children:'The student\'s answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response "Your answer is not fully expanded and simplified."'})]}),checked:this.props.simplify,onChange:this.props.onChangeSimplify})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.buttonRow,styles$O.paddedY),children:removeButton})]})}constructor(...args){super(...args),this.state={deleteFocused:false},this.handleImSure=()=>{this.props.onDelete();this.handleCancelDelete();},this.handleCancelDelete=()=>{this.setState({deleteFocused:false});},this.handleDelete=()=>{this.setState({deleteFocused:true});},this.toggleConsidered=()=>{const newVal=findNextIn(PerseusExpressionAnswerFormConsidered,this.props.considered);this.props.onChangeConsidered(newVal);};}}const styles$O=StyleSheet.create({paddedX:{paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8},paddedY:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},answersSubtitle:{fontStyle:"italic"},answerOption:{border:"1px solid #ddd",borderRadius:"3px",display:"flex",flexDirection:"column"},answerStatusWrong:{backgroundColor:color.fadedRed16},answerStatusCorrect:{backgroundColor:color.fadedGreen16},answerStatusUngraded:{backgroundColor:color.fadedBlue16},buttonRow:{display:"flex"},deleteButton:{paddingInline:sizing.size_160}});const consideredButtonStyles={wrong:styles$O.answerStatusWrong,correct:styles$O.answerStatusCorrect,ungraded:styles$O.answerStatusUngraded};
1492
+ const{ButtonGroup: ButtonGroup$7,InfoTip: InfoTip$m}=components;const buttonSetsList=["basic","trig","prealgebra","logarithms","scientific","basic relations","advanced relations"];class ExpressionEditor extends React.Component{serialize(){const{answerForms,buttonSets,functions,times,visibleLabel,ariaLabel}=this.props;return {answerForms,buttonSets,functions,times,visibleLabel,ariaLabel,extraKeys:deriveExtraKeys(this.props)}}updateAnswerForm(index,answerFormProps){const answerForms=this.props.answerForms.slice();answerForms[index]=answerFormProps;const{extraKeys:_,...restProps}=this.props;const extraKeys=deriveExtraKeys({...restProps,answerForms});this.props.onChange({answerForms,extraKeys});}changeSimplify(index,simplify){const answerForm={...this.props.answerForms[index],simplify};this.updateAnswerForm(index,answerForm);}changeForm(index,form){const answerForm={...this.props.answerForms[index],form};this.updateAnswerForm(index,answerForm);}changeConsidered(index,considered){const answerForm={...this.props.answerForms[index],considered};this.updateAnswerForm(index,answerForm);}changeTimes(times){this.props.onChange({times:times});}render(){const answerOptions=this.props.answerForms.map((ans,index)=>{const expressionProps={times:this.props.times,functions:this.props.functions,buttonSets:this.props.buttonSets,buttonsVisible:"focused",userInput:ans.value,handleUserInput:input=>this.changeExpressionWidget(index,input),trackInteraction:()=>{},widgetId:this.props.widgetId+"-"+ans.key,visibleLabel:this.props.visibleLabel,ariaLabel:this.props.ariaLabel};return jsxRuntimeExports.jsx(AnswerOption,{considered:ans.considered,expressionProps:expressionProps,form:ans.form,simplify:ans.simplify,onDelete:()=>this.handleRemoveForm(index),onChangeSimplify:simplify=>this.changeSimplify(index,simplify),onChangeForm:form=>this.changeForm(index,form),onChangeConsidered:considered=>this.changeConsidered(index,considered)},ans.key)});const buttonSetChoices=buttonSetsList.map(name=>{const isBasic=name==="basic";const checked=this.props.buttonSets.includes(name)||isBasic;return jsxRuntimeExports.jsx(Checkbox$1,{label:name,checked:checked,disabled:isBasic,onChange:()=>this.handleButtonSet(name)},name)});buttonSetChoices.unshift(jsxRuntimeExports.jsx(Checkbox$1,{label:"show ÷ button",checked:this.props.buttonSets.includes("basic+div"),onChange:this.handleToggleDiv},"show ÷ button"));return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Global Options"}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Visible label",jsxRuntimeExports.jsx(InfoTip$m,{children:"Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."})]}),value:this.props.visibleLabel||"",onChange:this.handleVisibleLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Aria label",jsxRuntimeExports.jsxs(InfoTip$m,{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})]})]}),value:this.props.ariaLabel||"",onChange:this.handleAriaLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Function variables",jsxRuntimeExports.jsx(InfoTip$m,{children:'Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means "f of x" and not "f times x".'})]}),value:this.state.functionsInternal,onChange:this.handleFunctions})}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Use × instead of ⋅ for multiplication",jsxRuntimeExports.jsx(InfoTip$m,{children:"For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."})]}),checked:this.props.times,onChange:newCheckedState=>{this.changeTimes(newCheckedState);}})}),jsxRuntimeExports.jsxs("div",{className:css(styles$M.paddedY),children:[jsxRuntimeExports.jsx(HeadingXSmall,{children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(HeadingSmall,{children:"Answers"}),jsxRuntimeExports.jsx(Caption,{style:styles$M.answersSubtitle,children:"student responses area matched against these from top to bottom"}),jsxRuntimeExports.jsx(View,{style:{gap:spacing.xSmall_8},children:answerOptions}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.newAnswer,children:"Add new answer"})]})}constructor(props){super(props),this.getSaveWarnings=()=>{const issues=[];if(this.props.answerForms.length===0){issues.push("No answers specified");}else {const hasCorrect=this.props.answerForms.some(form=>{return form.considered==="correct"});if(!hasCorrect){issues.push("No correct answer specified");}_(this.props.answerForms).each((form,ix)=>{if(this.props.value===""){issues.push(`Answer ${ix+1} is empty`);}else {const expression=KAS.parse(form.value,{functions:this.props.functions});if(!expression.parsed){issues.push(`Couldn't parse ${form.value}`);}else if(form.simplify&&!expression.expr.isSimplified()){issues.push(`${form.value} isn't simplified, but is required" +
1493
+ " to be`);}}});}return issues},this.newAnswer=()=>{const answerForms=this.props.answerForms.slice();const newKey=crypto.randomUUID();const newAnswerForm={considered:"correct",form:false,key:`${newKey}`,simplify:false,value:""};answerForms.push(newAnswerForm);this.props.onChange({answerForms});},this.handleRemoveForm=i=>{const updatedAnswerForms=this.props.answerForms.slice();updatedAnswerForms.splice(i,1);this.props.onChange({answerForms:updatedAnswerForms});},this.handleButtonSet=changingName=>{const buttonSetNames=buttonSetsList;const buttonSets=buttonSetNames.filter(set=>{return this.props.buttonSets.includes(set)!==(set===changingName)});this.props.onChange({buttonSets});},this.handleToggleDiv=()=>{let keep;let remove;if(this.props.buttonSets.includes("basic+div")){keep="basic";remove="basic+div";}else {keep="basic+div";remove="basic";}const buttonSets=this.props.buttonSets.filter(set=>set!==remove).concat(keep);this.props.onChange({buttonSets});},this.handleTexInsert=str=>{this.refs.expression.insert(str);},this.handleFunctions=value=>{this.setState({functionsInternal:value});const newProps={};newProps.functions=value.split(/[ ,]+/).filter(isTruthy);this.props.onChange(newProps);},this.handleVisibleLabel=visibleLabel=>{this.props.onChange({visibleLabel});},this.handleAriaLabel=ariaLabel=>{this.props.onChange({ariaLabel});},this.changeExpressionWidget=(index,input)=>{const answerForm={...this.props.answerForms[index],value:input};this.updateAnswerForm(index,answerForm);};this.state={functionsInternal:this.props.functions.join(" ")};}}ExpressionEditor.widgetName="expression";ExpressionEditor.defaultProps=expressionLogic.defaultWidgetOptions;const findNextIn=function(arr,val){let ix=arr.indexOf(val);ix=(ix+1)%arr.length;return arr[ix]};class AnswerOption extends React.Component{render(){const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",style:styles$M.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$M.answerOption),children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,value:this.props.considered,selectedButtonStyle:consideredButtonStyles[this.props.considered],buttons:PerseusExpressionAnswerFormConsidered.map(c=>({value:c,content:c,title:`This answer will be considered ${c}`}))}),jsxRuntimeExports.jsx(Expression,{...this.props.expressionProps}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY,styles$M.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip$m,{children:"The student's answer must be in the same form. Commutativity and excess negative signs are ignored."})]}),checked:this.props.form,onChange:this.props.onChangeForm})}),jsxRuntimeExports.jsx("div",{className:css(styles$M.paddedY,styles$M.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip$m,{children:'The student\'s answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response "Your answer is not fully expanded and simplified."'})]}),checked:this.props.simplify,onChange:this.props.onChangeSimplify})}),jsxRuntimeExports.jsx("div",{className:css(styles$M.buttonRow,styles$M.paddedY),children:removeButton})]})}constructor(...args){super(...args),this.state={deleteFocused:false},this.handleImSure=()=>{this.props.onDelete();this.handleCancelDelete();},this.handleCancelDelete=()=>{this.setState({deleteFocused:false});},this.handleDelete=()=>{this.setState({deleteFocused:true});},this.toggleConsidered=()=>{const newVal=findNextIn(PerseusExpressionAnswerFormConsidered,this.props.considered);this.props.onChangeConsidered(newVal);};}}const styles$M=StyleSheet.create({paddedX:{paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8},paddedY:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},answersSubtitle:{fontStyle:"italic"},answerOption:{border:"1px solid #ddd",borderRadius:"3px",display:"flex",flexDirection:"column"},answerStatusWrong:{backgroundColor:color.fadedRed16},answerStatusCorrect:{backgroundColor:color.fadedGreen16},answerStatusUngraded:{backgroundColor:color.fadedBlue16},buttonRow:{display:"flex"},deleteButton:{paddingInline:sizing.size_160}});const consideredButtonStyles={wrong:styles$M.answerStatusWrong,correct:styles$M.answerStatusCorrect,ungraded:styles$M.answerStatusUngraded};
1493
1494
 
1494
- class FreeResponseEditor extends React.Component{render(){return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Question"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.question,onChange:e=>this.props.onChange({question:e.target.value})}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Placeholder"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.placeholder,onChange:e=>this.props.onChange({placeholder:e.target.value})}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Allow unlimited characters"}),field:jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.allowUnlimitedCharacters,onChange:val=>this.props.onChange({allowUnlimitedCharacters:val})}),styles:{root:styles$N.labeledInputField}}),!this.props.allowUnlimitedCharacters&&jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Character limit"}),field:jsxRuntimeExports.jsx("input",{type:"number",min:1,value:this.props.characterLimit,onChange:this.handleUpdateCharacterLimit}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Scoring criteria"}),jsxRuntimeExports.jsx(View,{style:styles$N.criteriaList,children:this.renderCriteriaList()}),jsxRuntimeExports.jsx(View,{children:jsxRuntimeExports.jsx(Button,{onClick:this.handleAddCriterion,startIcon:plusCircle,children:"Add an item"})})]})]})}constructor(...args){super(...args),this.serialize=()=>{return {allowUnlimitedCharacters:this.props.allowUnlimitedCharacters,characterLimit:this.props.characterLimit,placeholder:this.props.placeholder,question:this.props.question,scoringCriteria:this.props.scoringCriteria}},this.getSaveWarnings=()=>{const warnings=[];if(!this.props.question){warnings.push("The question is empty");}if(this.props.question.match(Util.rWidgetRule)!=null){warnings.push("The question contains a widget");}return warnings},this.handleUpdateCharacterLimit=e=>{const val=parseInt(e.target.value);if(isNaN(val)){return}this.props.onChange({characterLimit:Math.max(1,val)});},this.handleUpdateCriterion=(index,criterion)=>{const newCriteria=this.props.scoringCriteria.map((c,i)=>{if(i===index){return criterion}return c});this.props.onChange({scoringCriteria:newCriteria});},this.handleDeleteCriterion=index=>{this.props.onChange({scoringCriteria:this.props.scoringCriteria.filter((_,i)=>i!==index)});},this.handleAddCriterion=()=>{this.props.onChange({scoringCriteria:[...this.props.scoringCriteria,{text:""}]});},this.renderCriteriaList=()=>{const isDeletable=this.props.scoringCriteria.length>1;return this.props.scoringCriteria.map((criterion,index)=>{return jsxRuntimeExports.jsx(CriterionEditor,{criterion:criterion,index:index,isDeletable:isDeletable,onChange:this.handleUpdateCriterion,onDelete:this.handleDeleteCriterion},index)})};}}FreeResponseEditor.defaultProps=freeResponseLogic.defaultWidgetOptions;FreeResponseEditor.widgetName="free-response";const CriterionEditor=function(props){return jsxRuntimeExports.jsxs(View,{style:styles$N.criterionContainer,children:[jsxRuntimeExports.jsx("textarea",{"aria-label":`Criterion ${props.index+1}`,onChange:e=>props.onChange(props.index,{text:e.target.value}),value:props.criterion.text}),props.isDeletable&&jsxRuntimeExports.jsx(View,{style:styles$N.deleteButtonContainer,children:jsxRuntimeExports.jsx(Button,{"aria-label":`Delete criterion ${props.index+1}`,actionType:"destructive",disabled:!props.isDeletable,kind:"tertiary",onClick:()=>props.onDelete(props.index),size:"small",startIcon:trashIcon,children:"Delete"})})]})};const styles$N=StyleSheet.create({criteriaList:{gap:spacing.small_12},criterionContainer:{paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${semanticColor.core.border.neutral.subtle}`,":last-child":{borderBottom:"none"}},deleteButtonContainer:{display:"flex",flexDirection:"row",justifyContent:"flex-end"},labeledInputField:{paddingBottom:spacing.large_24}});
1495
+ class FreeResponseEditor extends React.Component{render(){return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Question"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.question,onChange:e=>this.props.onChange({question:e.target.value})}),styles:{root:styles$L.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Placeholder"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.placeholder,onChange:e=>this.props.onChange({placeholder:e.target.value})}),styles:{root:styles$L.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Allow unlimited characters"}),field:jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.allowUnlimitedCharacters,onChange:val=>this.props.onChange({allowUnlimitedCharacters:val})}),styles:{root:styles$L.labeledInputField}}),!this.props.allowUnlimitedCharacters&&jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Character limit"}),field:jsxRuntimeExports.jsx("input",{type:"number",min:1,value:this.props.characterLimit,onChange:this.handleUpdateCharacterLimit}),styles:{root:styles$L.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Scoring criteria"}),jsxRuntimeExports.jsx(View,{style:styles$L.criteriaList,children:this.renderCriteriaList()}),jsxRuntimeExports.jsx(View,{children:jsxRuntimeExports.jsx(Button,{onClick:this.handleAddCriterion,startIcon:plusCircle,children:"Add an item"})})]})]})}constructor(...args){super(...args),this.serialize=()=>{return {allowUnlimitedCharacters:this.props.allowUnlimitedCharacters,characterLimit:this.props.characterLimit,placeholder:this.props.placeholder,question:this.props.question,scoringCriteria:this.props.scoringCriteria}},this.getSaveWarnings=()=>{const warnings=[];if(!this.props.question){warnings.push("The question is empty");}if(this.props.question.match(Util.rWidgetRule)!=null){warnings.push("The question contains a widget");}return warnings},this.handleUpdateCharacterLimit=e=>{const val=parseInt(e.target.value);if(isNaN(val)){return}this.props.onChange({characterLimit:Math.max(1,val)});},this.handleUpdateCriterion=(index,criterion)=>{const newCriteria=this.props.scoringCriteria.map((c,i)=>{if(i===index){return criterion}return c});this.props.onChange({scoringCriteria:newCriteria});},this.handleDeleteCriterion=index=>{this.props.onChange({scoringCriteria:this.props.scoringCriteria.filter((_,i)=>i!==index)});},this.handleAddCriterion=()=>{this.props.onChange({scoringCriteria:[...this.props.scoringCriteria,{text:""}]});},this.renderCriteriaList=()=>{const isDeletable=this.props.scoringCriteria.length>1;return this.props.scoringCriteria.map((criterion,index)=>{return jsxRuntimeExports.jsx(CriterionEditor,{criterion:criterion,index:index,isDeletable:isDeletable,onChange:this.handleUpdateCriterion,onDelete:this.handleDeleteCriterion},index)})};}}FreeResponseEditor.defaultProps=freeResponseLogic.defaultWidgetOptions;FreeResponseEditor.widgetName="free-response";const CriterionEditor=function(props){return jsxRuntimeExports.jsxs(View,{style:styles$L.criterionContainer,children:[jsxRuntimeExports.jsx("textarea",{"aria-label":`Criterion ${props.index+1}`,onChange:e=>props.onChange(props.index,{text:e.target.value}),value:props.criterion.text}),props.isDeletable&&jsxRuntimeExports.jsx(View,{style:styles$L.deleteButtonContainer,children:jsxRuntimeExports.jsx(Button,{"aria-label":`Delete criterion ${props.index+1}`,actionType:"destructive",disabled:!props.isDeletable,kind:"tertiary",onClick:()=>props.onDelete(props.index),size:"small",startIcon:trashIcon,children:"Delete"})})]})};const styles$L=StyleSheet.create({criteriaList:{gap:spacing.small_12},criterionContainer:{paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${semanticColor.core.border.neutral.subtle}`,":last-child":{borderBottom:"none"}},deleteButtonContainer:{display:"flex",flexDirection:"row",justifyContent:"flex-end"},labeledInputField:{paddingBottom:spacing.large_24}});
1495
1496
 
1496
- const{InlineIcon: InlineIcon$2,TextInput: TextInput$5}=components;class GradedGroupEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{className:css(styles$M.title),children:["Title:"," ",jsxRuntimeExports.jsx(TextInput$5,{value:this.props.title,className:css(styles$M.input),onChange:this.change("title")})]})}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,content:this.props.content,widgets:this.props.widgets,apiOptions:this.props.apiOptions,images:this.props.images,widgetEnabled:true,immutableWidgets:false,onChange:this.props.onChange,warnNoPrompt:true,warnNoWidgets:true}),!this.props.hint&&jsxRuntimeExports.jsxs("button",{type:"button",style:{marginTop:10},className:"add-hint simple-button orange",onClick:this.handleAddHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconPlus})," Add a hint"]}),this.props.hint&&jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor",children:[jsxRuntimeExports.jsx("div",{className:css(styles$M.hintsTitle),children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.hintEditor,content:this.props.hint?this.props.hint.content:"",widgets:this.props.hint?this.props.hint.widgets:{},apiOptions:this.props.apiOptions,images:this.props.hint&&this.props.hint.images,widgetEnabled:true,immutableWidgets:false,onChange:props=>{this.change("hint",Object.assign({},this.props.hint,props));}}),jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.handleRemoveHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconTrash})," Remove this hint"]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.hintEditor=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAddHint=()=>{const hint={content:"",images:{},widgets:{}};this.props.onChange({hint},()=>{this.hintEditor.current?.focus();});},this.handleRemoveHint=e=>{this.props.onChange({hint:null});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=()=>{return {title:this.props.title,...this.editor.current?.serialize(),hint:this.hintEditor.current?.serialize()}};}}GradedGroupEditor.propTypes={...Changeable.propTypes,title:PropTypes.string,content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GradedGroupEditor.widgetName="graded-group";GradedGroupEditor.defaultProps=gradedGroupLogic.defaultWidgetOptions;const styles$M=StyleSheet.create({title:{fontSize:18,fontWeight:"bold"},input:{fontSize:18},hintsTitle:{marginTop:10,fontSize:"110%",fontWeight:"bold"}});
1497
+ const{InlineIcon: InlineIcon$2,TextInput: TextInput$5}=components;class GradedGroupEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{className:css(styles$K.title),children:["Title:"," ",jsxRuntimeExports.jsx(TextInput$5,{value:this.props.title,className:css(styles$K.input),onChange:this.change("title")})]})}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,content:this.props.content,widgets:this.props.widgets,apiOptions:this.props.apiOptions,images:this.props.images,widgetEnabled:true,immutableWidgets:false,onChange:this.props.onChange,warnNoPrompt:true,warnNoWidgets:true}),!this.props.hint&&jsxRuntimeExports.jsxs("button",{type:"button",style:{marginTop:10},className:"add-hint simple-button orange",onClick:this.handleAddHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconPlus})," Add a hint"]}),this.props.hint&&jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor",children:[jsxRuntimeExports.jsx("div",{className:css(styles$K.hintsTitle),children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.hintEditor,content:this.props.hint?this.props.hint.content:"",widgets:this.props.hint?this.props.hint.widgets:{},apiOptions:this.props.apiOptions,images:this.props.hint&&this.props.hint.images,widgetEnabled:true,immutableWidgets:false,onChange:props=>{this.change("hint",Object.assign({},this.props.hint,props));}}),jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.handleRemoveHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconTrash})," Remove this hint"]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.hintEditor=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAddHint=()=>{const hint={content:"",images:{},widgets:{}};this.props.onChange({hint},()=>{this.hintEditor.current?.focus();});},this.handleRemoveHint=e=>{this.props.onChange({hint:null});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=()=>{return {title:this.props.title,...this.editor.current?.serialize(),hint:this.hintEditor.current?.serialize()}};}}GradedGroupEditor.propTypes={...Changeable.propTypes,title:PropTypes.string,content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GradedGroupEditor.widgetName="graded-group";GradedGroupEditor.defaultProps=gradedGroupLogic.defaultWidgetOptions;const styles$K=StyleSheet.create({title:{fontSize:18,fontWeight:"bold"},input:{fontSize:18},hintsTitle:{marginTop:10,fontSize:"110%",fontWeight:"bold"}});
1497
1498
 
1498
1499
  class GradedGroupSetEditor extends React.Component{UNSAFE_componentWillMount(){this._editors=[];}render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[this.renderGroups(),jsxRuntimeExports.jsx("button",{onClick:this.addGroup,children:"Add group"})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.getSaveWarnings=()=>{return [].concat(...this._editors.map(editor=>editor?editor.getSaveWarnings():[]))},this.serialize=()=>{return {gradedGroups:this.props.gradedGroups}},this.renderGroups=()=>{if(!this.props.gradedGroups){return null}return this.props.gradedGroups.map((group,i)=>jsxRuntimeExports.jsx(GradedGroupEditor,{ref:el=>this._editors[i]=el,...group,apiOptions:this.props.apiOptions,widgetEnabled:true,immutableWidgets:false,onChange:data=>this.change("gradedGroups",setArrayItem(this.props.gradedGroups,i,{...this.props.gradedGroups[i],...data}))},i))},this.addGroup=()=>{const groups=this.props.gradedGroups||[];this.change("gradedGroups",groups.concat([GradedGroupEditor.defaultProps]));};}}GradedGroupSetEditor.propTypes={...Changeable.propTypes,apiOptions:ApiOptions.propTypes,gradedGroups:PropTypes.array,onChange:PropTypes.func.isRequired};GradedGroupSetEditor.widgetName="graded-group-set";GradedGroupSetEditor.defaultProps=gradedGroupSetLogic.defaultWidgetOptions;const setArrayItem=(list,i,value)=>[...list.slice(0,i),value,...list.slice(i+1)];
1499
1500
 
1500
- const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$k,RangeInput: RangeInput$6}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}change(...args){return Changeable.change.apply(this,args)}changeRulerLabel(e){this.change({rulerLabel:e.target.value});}changeRulerTicks(e){this.change({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"canvas-size",value:this.props.box,onChange:box=>{this.change({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$k,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.change({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.change=this.change.bind(this);this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1501
+ const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$l,RangeInput: RangeInput$6}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}change(...args){return Changeable.change.apply(this,args)}changeRulerLabel(e){this.change({rulerLabel:e.target.value});}changeRulerTicks(e){this.change({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"canvas-size",value:this.props.box,onChange:box=>{this.change({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$6,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$l,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.change({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.change=this.change.bind(this);this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1501
1502
 
1502
- const{InfoTip: InfoTip$j,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,handleUserInput:(userInput,cb)=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct},cb);},availableTypes:this.props.availableTypes,trackInteraction:function(){}};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$j,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:this.change("graph")}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.propTypes={...Changeable.propTypes};GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1503
+ const{InfoTip: InfoTip$k,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,handleUserInput:(userInput,cb)=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct},cb);},availableTypes:this.props.availableTypes,trackInteraction:function(){}};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$k,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:this.change("graph")}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.propTypes={...Changeable.propTypes};GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1503
1504
 
1504
1505
  class GroupEditor extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"perseus-group-editor",children:jsxRuntimeExports.jsx(Editor,{ref:this.editor,content:this.props.content,widgets:this.props.widgets,apiOptions:this.props.apiOptions,images:this.props.images,widgetEnabled:true,immutableWidgets:false,onChange:this.props.onChange})})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=()=>{return _.extend({},this.editor.current?.serialize())};}}GroupEditor.propTypes={content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GroupEditor.widgetName="group";GroupEditor.defaultProps=groupLogic.defaultWidgetOptions;
1505
1506
 
1506
1507
  class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{children:[jsxRuntimeExports.jsxs("label",{children:["Name:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:["Value:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PairEditor.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor.defaultProps={name:"",value:""};class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PairsEditor.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};class IframeEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{style:{fontWeight:"bold",textAlign:"center"},children:["This widget is deprecated! ",jsxRuntimeExports.jsx("br",{}),"Try using the Video or CS Program widgets instead."]}),jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.url,onChange:this.change("url")})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor,{name:"settings",pairs:this.props.settings,onChange:this.handleSettingsChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Width:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.width,onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("label",{children:["Height:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.height,onChange:this.change("height")})]}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Allow full screen",checked:this.props.allowFullScreen,onChange:value=>{this.props.onChange({allowFullScreen:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Allow iframe content to redirect the page",checked:this.props.allowTopNavigation,onChange:value=>{this.props.onChange({allowTopNavigation:value});}})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}IframeEditor.propTypes={...Changeable.propTypes};IframeEditor.widgetName="iframe";IframeEditor.defaultProps=iframeLogic.defaultWidgetOptions;
1507
1508
 
1508
- const{InfoTip: InfoTip$i,InlineIcon: InlineIcon$1,RangeInput: RangeInput$5}=components;const INTERNALLY_HOSTED_DOMAINS="("+"ka-.*.s3.amazonaws.com|"+"(fastly|cdn).kastatic.org|"+"khanacademy.org|"+"kasandbox.org"+")";const INTERNALLY_HOSTED_URL_RE=new RegExp("^(https?|web\\+graphie)://[^/]*"+INTERNALLY_HOSTED_DOMAINS);const captionAlignments=["center","above","above right","right","below right","below","below left","left","above left"];class ImageEditor extends React.Component{componentDidMount(){this._isMounted=true;}componentWillUnmount(){this._isMounted=false;}_renderRowForLabel(label,i){return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(RangeInput$5,{value:label.coordinates,onChange:this.onCoordinateChange.bind(this,i)})}),jsxRuntimeExports.jsx("td",{style:{verticalAlign:"bottom",width:"5px"},children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",value:label.content,onChange:this.onContentChange.bind(this,i)})}),jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx("select",{className:"perseus-widget-dropdown",value:label.alignment,onChange:this.onAlignmentChange.bind(this,i),children:captionAlignments.map(function(alignment,i){return jsxRuntimeExports.jsx("option",{value:alignment,children:alignment},""+i)},this)})}),jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx("a",{href:"#",className:"simple-button orange delete-label",title:"Remove this label",onClick:this.removeLabel.bind(this,i),children:jsxRuntimeExports.jsx(InlineIcon$1,{...iconTrash})})})]},i)}removeLabel(labelIndex,e){e.preventDefault();const labels=[...this.props.labels];labels.splice(labelIndex,1);this.props.onChange({labels:labels});}onCoordinateChange(labelIndex,newCoordinates){const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{coordinates:newCoordinates});this.props.onChange({labels:labels});}onContentChange(labelIndex,e){const newContent=e.target.value;const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{content:newContent});this.props.onChange({labels:labels});}onAlignmentChange(labelIndex,e){const newAlignment=e.target.value;const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{alignment:newAlignment});this.props.onChange({labels:labels});}setUrl(url,width,height,silent){if(!this._isMounted){return}const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;const box=[image.width,image.height];this.props.onChange({backgroundImage:image,box:box},null,silent);}async onUrlChange(url,silent){if(!url){this.setUrl(url,0,0,silent);return}if(!INTERNALLY_HOSTED_URL_RE.test(url)){this.setState({backgroundImageError:"Images must be from sites hosted by Khan Academy. "+"Please input a Khan Academy-owned address, or use the "+"Add Image tool to rehost an existing image"});return}this.setState({backgroundImageError:""});try{const size=await Util.getImageSizeModern(url);this.setUrl(url,size[0],size[1],true);}catch(error){this.setState({backgroundImageError:`There was an error loading the image URL: ${JSON.stringify(error,null,2)}`});}}onRangeChange(type,newRange){const range=this.props.range.slice();range[type]=newRange;this.props.onChange({range:range});}serialize(){return EditorJsonify.serialize.call(this)}render(){const backgroundImage=this.props.backgroundImage;const imageSettings=jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[!Util.isLabeledSVG(backgroundImage.url)&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Preview:"}),jsxRuntimeExports.jsx("img",{alt:"Editor preview of image",src:backgroundImage.url,style:{width:"100%"}})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Dimensions:"}),jsxRuntimeExports.jsxs("p",{children:[backgroundImage.width,"x",backgroundImage.height]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsxs("div",{children:["Alt text:",jsxRuntimeExports.jsx(InfoTip$i,{children:"This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported)."})]}),jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.alt,onChange:props=>{if(props.content!=null){this.change("alt",props.content);}},widgetEnabled:false})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Caption:"}),jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.caption,onChange:props=>{if(props.content!=null){this.change("caption",props.content);}},widgetEnabled:false})]})})]});const backgroundImageErrorText=jsxRuntimeExports.jsx("div",{className:"renderer-widget-error",children:this.state.backgroundImageError});return jsxRuntimeExports.jsxs("div",{className:"perseus-image-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Image url:",jsxRuntimeExports.jsx(InfoTip$i,{children:"Paste an image or graphie image URL."}),this.state.backgroundImageError&&backgroundImageErrorText,jsxRuntimeExports.jsx(BlurInput,{value:backgroundImage.url||"",style:{width:332},onChange:url=>this.onUrlChange(url,false)})]}),backgroundImage.url&&imageSettings]})}constructor(...args){super(...args),this._isMounted=false,this.state={backgroundImageError:""},this.change=(...args)=>{return Changeable.change.apply(this,args)};}}ImageEditor.displayName="ImageEditor";ImageEditor.widgetName="image";ImageEditor.defaultProps=imageLogic.defaultWidgetOptions;
1509
+ const{InfoTip: InfoTip$j,InlineIcon: InlineIcon$1,RangeInput: RangeInput$5}=components;const INTERNALLY_HOSTED_DOMAINS="("+"ka-.*.s3.amazonaws.com|"+"(fastly|cdn).kastatic.org|"+"khanacademy.org|"+"kasandbox.org"+")";const INTERNALLY_HOSTED_URL_RE=new RegExp("^(https?|web\\+graphie)://[^/]*"+INTERNALLY_HOSTED_DOMAINS);const captionAlignments=["center","above","above right","right","below right","below","below left","left","above left"];class ImageEditor extends React.Component{componentDidMount(){this._isMounted=true;}componentWillUnmount(){this._isMounted=false;}_renderRowForLabel(label,i){return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(RangeInput$5,{value:label.coordinates,onChange:this.onCoordinateChange.bind(this,i)})}),jsxRuntimeExports.jsx("td",{style:{verticalAlign:"bottom",width:"5px"},children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",value:label.content,onChange:this.onContentChange.bind(this,i)})}),jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx("select",{className:"perseus-widget-dropdown",value:label.alignment,onChange:this.onAlignmentChange.bind(this,i),children:captionAlignments.map(function(alignment,i){return jsxRuntimeExports.jsx("option",{value:alignment,children:alignment},""+i)},this)})}),jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx("a",{href:"#",className:"simple-button orange delete-label",title:"Remove this label",onClick:this.removeLabel.bind(this,i),children:jsxRuntimeExports.jsx(InlineIcon$1,{...iconTrash})})})]},i)}removeLabel(labelIndex,e){e.preventDefault();const labels=[...this.props.labels];labels.splice(labelIndex,1);this.props.onChange({labels:labels});}onCoordinateChange(labelIndex,newCoordinates){const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{coordinates:newCoordinates});this.props.onChange({labels:labels});}onContentChange(labelIndex,e){const newContent=e.target.value;const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{content:newContent});this.props.onChange({labels:labels});}onAlignmentChange(labelIndex,e){const newAlignment=e.target.value;const labels=this.props.labels.slice();labels[labelIndex]=_.extend({},labels[labelIndex],{alignment:newAlignment});this.props.onChange({labels:labels});}setUrl(url,width,height,silent){if(!this._isMounted){return}const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;const box=[image.width,image.height];this.props.onChange({backgroundImage:image,box:box},null,silent);}async onUrlChange(url,silent){if(!url){this.setUrl(url,0,0,silent);return}if(!INTERNALLY_HOSTED_URL_RE.test(url)){this.setState({backgroundImageError:"Images must be from sites hosted by Khan Academy. "+"Please input a Khan Academy-owned address, or use the "+"Add Image tool to rehost an existing image"});return}this.setState({backgroundImageError:""});try{const size=await Util.getImageSizeModern(url);this.setUrl(url,size[0],size[1],true);}catch(error){this.setState({backgroundImageError:`There was an error loading the image URL: ${JSON.stringify(error,null,2)}`});}}onRangeChange(type,newRange){const range=this.props.range.slice();range[type]=newRange;this.props.onChange({range:range});}serialize(){return EditorJsonify.serialize.call(this)}render(){const backgroundImage=this.props.backgroundImage;const imageSettings=jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[!Util.isLabeledSVG(backgroundImage.url)&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Preview:"}),jsxRuntimeExports.jsx("img",{alt:"Editor preview of image",src:backgroundImage.url,style:{width:"100%"}})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Dimensions:"}),jsxRuntimeExports.jsxs("p",{children:[backgroundImage.width,"x",backgroundImage.height]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsxs("div",{children:["Alt text:",jsxRuntimeExports.jsx(InfoTip$j,{children:"This is important for screenreaders. The content of this alt text will be formatted as markdown (tables, emphasis, etc. are supported)."})]}),jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.alt,onChange:props=>{if(props.content!=null){this.change("alt",props.content);}},widgetEnabled:false})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("div",{children:"Caption:"}),jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.caption,onChange:props=>{if(props.content!=null){this.change("caption",props.content);}},widgetEnabled:false})]})})]});const backgroundImageErrorText=jsxRuntimeExports.jsx("div",{className:"renderer-widget-error",children:this.state.backgroundImageError});return jsxRuntimeExports.jsxs("div",{className:"perseus-image-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Image url:",jsxRuntimeExports.jsx(InfoTip$j,{children:"Paste an image or graphie image URL."}),this.state.backgroundImageError&&backgroundImageErrorText,jsxRuntimeExports.jsx(BlurInput,{value:backgroundImage.url||"",style:{width:332},onChange:url=>this.onUrlChange(url,false)})]}),backgroundImage.url&&imageSettings]})}constructor(...args){super(...args),this._isMounted=false,this.state={backgroundImageError:""},this.change=(...args)=>{return Changeable.change.apply(this,args)};}}ImageEditor.displayName="ImageEditor";ImageEditor.widgetName="image";ImageEditor.defaultProps=imageLogic.defaultWidgetOptions;
1509
1510
 
1510
- const{InfoTip: InfoTip$h}=components;class InputNumberEditor extends React.Component{render(){const answerTypeOptions=_.map(inputNumberAnswerTypes,function(v,k){return jsxRuntimeExports.jsx("option",{value:k,children:v.name},k)},this);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Correct answer:"," ",jsxRuntimeExports.jsx(BlurInput,{value:""+this.props.value,onChange:this.handleAnswerChange,ref:this.input})]})}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Unsimplified answers"," ",jsxRuntimeExports.jsxs("select",{value:this.props.simplify,onChange:e=>{this.props.onChange({simplify:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"required",children:"will not be graded"}),jsxRuntimeExports.jsx("option",{value:"optional",children:"will be accepted"}),jsxRuntimeExports.jsx("option",{value:"enforced",children:"will be marked wrong"})]})]}),jsxRuntimeExports.jsxs(InfoTip$h,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "will not be graded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be marked wrong" only if we are specifically assessing the ability to simplify.'})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.inexact,onChange:e=>{this.props.onChange({inexact:e.target.checked});}})," ","Allow inexact answers"]}),jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",style:{visibility:"hidden"}}),"Max error:"," ",jsxRuntimeExports.jsx("input",{type:"text",disabled:!this.props.inexact,defaultValue:this.props.maxError,"aria-label":"Max error",onBlur:e=>{const ans=""+(Util.firstNumericalParse(e.target.value)||0);e.target.value=ans;this.props.onChange({maxError:ans});}})]})]}),jsxRuntimeExports.jsxs("div",{children:["Answer type:"," ",jsxRuntimeExports.jsx("select",{value:this.props.answerType,onChange:e=>{this.props.onChange({answerType:e.target.value});},"aria-label":"Answer type",children:answerTypeOptions}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:'Use the default "Numbers" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions).'})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Width"," ",jsxRuntimeExports.jsxs("select",{value:this.props.size,onChange:e=>{this.props.onChange({size:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"normal",children:"Normal (80px)"}),jsxRuntimeExports.jsx("option",{value:"small",children:"Small (40px)"})]})]}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.rightAlign,onChange:e=>{this.props.onChange({rightAlign:e.target.checked});}})," ","Right alignment"]})})]})}constructor(...args){super(...args),this.input=React.createRef(),this.handleAnswerChange=str=>{const value=Util.firstNumericalParse(str)||0;this.props.onChange({value:value});},this.focus=()=>{this.input.current?.focus();return true},this.serialize=()=>({value:this.props.value,simplify:this.props.simplify,size:this.props.size,inexact:this.props.inexact,maxError:this.props.maxError,answerType:this.props.answerType,rightAlign:this.props.rightAlign});}}InputNumberEditor.widgetName="input-number";InputNumberEditor.defaultProps=inputNumberLogic.defaultWidgetOptions;
1511
+ const{InfoTip: InfoTip$i}=components;class InputNumberEditor extends React.Component{render(){const answerTypeOptions=_.map(inputNumberAnswerTypes,function(v,k){return jsxRuntimeExports.jsx("option",{value:k,children:v.name},k)},this);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Correct answer:"," ",jsxRuntimeExports.jsx(BlurInput,{value:""+this.props.value,onChange:this.handleAnswerChange,ref:this.input})]})}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Unsimplified answers"," ",jsxRuntimeExports.jsxs("select",{value:this.props.simplify,onChange:e=>{this.props.onChange({simplify:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"required",children:"will not be graded"}),jsxRuntimeExports.jsx("option",{value:"optional",children:"will be accepted"}),jsxRuntimeExports.jsx("option",{value:"enforced",children:"will be marked wrong"})]})]}),jsxRuntimeExports.jsxs(InfoTip$i,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "will not be graded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be marked wrong" only if we are specifically assessing the ability to simplify.'})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.inexact,onChange:e=>{this.props.onChange({inexact:e.target.checked});}})," ","Allow inexact answers"]}),jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",style:{visibility:"hidden"}}),"Max error:"," ",jsxRuntimeExports.jsx("input",{type:"text",disabled:!this.props.inexact,defaultValue:this.props.maxError,"aria-label":"Max error",onBlur:e=>{const ans=""+(Util.firstNumericalParse(e.target.value)||0);e.target.value=ans;this.props.onChange({maxError:ans});}})]})]}),jsxRuntimeExports.jsxs("div",{children:["Answer type:"," ",jsxRuntimeExports.jsx("select",{value:this.props.answerType,onChange:e=>{this.props.onChange({answerType:e.target.value});},"aria-label":"Answer type",children:answerTypeOptions}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Use the default "Numbers" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions).'})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Width"," ",jsxRuntimeExports.jsxs("select",{value:this.props.size,onChange:e=>{this.props.onChange({size:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"normal",children:"Normal (80px)"}),jsxRuntimeExports.jsx("option",{value:"small",children:"Small (40px)"})]})]}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.rightAlign,onChange:e=>{this.props.onChange({rightAlign:e.target.checked});}})," ","Right alignment"]})})]})}constructor(...args){super(...args),this.input=React.createRef(),this.handleAnswerChange=str=>{const value=Util.firstNumericalParse(str)||0;this.props.onChange({value:value});},this.focus=()=>{this.input.current?.focus();return true},this.serialize=()=>({value:this.props.value,simplify:this.props.simplify,size:this.props.size,inexact:this.props.inexact,maxError:this.props.maxError,answerType:this.props.answerType,rightAlign:this.props.rightAlign});}}InputNumberEditor.widgetName="input-number";InputNumberEditor.defaultProps=inputNumberLogic.defaultWidgetOptions;
1511
1512
 
1512
1513
  const{InlineIcon}=components;class ElementContainer extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-interaction-element",children:[jsxRuntimeExports.jsxs("a",{href:"#",className:"perseus-interaction-element-title "+(this.state.show?"open":"closed"),onClick:this.toggle,children:[this.state.show?jsxRuntimeExports.jsx(InlineIcon,{...iconChevronDown}):jsxRuntimeExports.jsx(InlineIcon,{...iconChevronRight}),this.props.title]}),jsxRuntimeExports.jsxs("div",{className:"perseus-interaction-element-content "+(this.state.show?"enter":"leave"),children:[this.props.children,(this.props.onUp!=null||this.props.onDown!=null||this.props.onDelete!=null)&&jsxRuntimeExports.jsxs("div",{className:"edit-controls",children:[this.props.onUp!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onUp,children:jsxRuntimeExports.jsx(InlineIcon,{...iconCircleArrowUp})}),this.props.onDown!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onDown,children:jsxRuntimeExports.jsx(InlineIcon,{...iconCircleArrowDown})}),this.props.onDelete!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onDelete,children:jsxRuntimeExports.jsx(InlineIcon,{...iconTrash})})]})]})]})}constructor(props){super(props),this.toggle=e=>{e.preventDefault();this.setState({show:!this.state.show});};this.state={show:props.initiallyVisible};}}ElementContainer.defaultProps={initiallyVisible:false,title:"More"};
1513
1514
 
@@ -1515,7 +1516,7 @@ const{ButtonGroup: ButtonGroup$5}=components;const COLORS=[KhanColors.BLACK,Khan
1515
1516
 
1516
1517
  const{ButtonGroup: ButtonGroup$4}=components;class DashPicker extends React.Component{render(){return jsxRuntimeExports.jsx(ButtonGroup$4,{value:this.props.value,allowEmpty:false,buttons:[{value:"",content:jsxRuntimeExports.jsx("span",{children:"—"})},{value:"-",content:jsxRuntimeExports.jsx("span",{children:"–––"})},{value:"- ",content:jsxRuntimeExports.jsx("span",{children:"–  –"})},{value:".",content:jsxRuntimeExports.jsx("span",{children:"····"})},{value:". ",content:jsxRuntimeExports.jsx("span",{children:"· · ·"})}],onChange:this.props.onChange})}}DashPicker.defaultProps={value:""};
1517
1518
 
1518
- function MathquillInput(props){const mathFieldWrapperRef=useRef(null);const mathFieldInstance=useRef();const{locale,strings}=useMathInputI18n();useEffect(()=>{if(mathFieldWrapperRef.current&&!mathFieldInstance.current){mathFieldInstance.current=createMathField(mathFieldWrapperRef.current,locale,strings,baseConfig=>({...baseConfig,handlers:{edit:mathField=>{let value=mathField.latex();value=value.replace(/<>/g,"\\ne");if(props.value!==value){props.onChange(value);}},upOutOf:mathField=>{mathField.typedText("^");}}}));}});return jsxRuntimeExports.jsx(View,{style:styles$L.outerWrapper,children:jsxRuntimeExports.jsx("span",{ref:mathFieldWrapperRef,className:"perseus-math-input mq-editable-field mq-math-mode"})})}const styles$L=StyleSheet.create({outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:color.offBlack50,borderRadius:3,background:color.white}});
1519
+ function MathquillInput(props){const mathFieldWrapperRef=useRef(null);const mathFieldInstance=useRef();const{locale,strings}=useMathInputI18n();useEffect(()=>{if(mathFieldWrapperRef.current&&!mathFieldInstance.current){mathFieldInstance.current=createMathField(mathFieldWrapperRef.current,locale,strings,baseConfig=>({...baseConfig,handlers:{edit:mathField=>{let value=mathField.latex();value=value.replace(/<>/g,"\\ne");if(props.value!==value){props.onChange(value);}},upOutOf:mathField=>{mathField.typedText("^");}}}));}});return jsxRuntimeExports.jsx(View,{style:styles$J.outerWrapper,children:jsxRuntimeExports.jsx("span",{ref:mathFieldWrapperRef,className:"perseus-math-input mq-editable-field mq-math-mode"})})}const styles$J=StyleSheet.create({outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:color.offBlack50,borderRadius:3,background:color.white}});
1519
1520
 
1520
1521
  const{NumberInput: NumberInput$d}=components;const{getDependencies: getDependencies$8}=Dependencies;class FunctionEditor extends React.Component{render(){const{TeX}=getDependencies$8();return jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(TeX,{children:this.props.funcName+"(x)="})," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.value,onChange:this.change("value")})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Range: ",jsxRuntimeExports.jsx(TeX,{children:"\\Large("}),jsxRuntimeExports.jsx(MathquillInput,{value:this.props.rangeMin,onChange:this.change("rangeMin")}),jsxRuntimeExports.jsx(TeX,{children:","})," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.rangeMax,onChange:this.change("rangeMax")}),jsxRuntimeExports.jsx(TeX,{children:"\\Large)"})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(ColorPicker,{value:this.props.color,onChange:this.change("color")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(DashPicker,{value:this.props.strokeDasharray,onChange:this.change("strokeDasharray")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:["Width:"," ",jsxRuntimeExports.jsx(NumberInput$d,{value:this.props.strokeWidth,placeholder:2,onChange:this.change("strokeWidth")})]})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}FunctionEditor.defaultProps={value:"x",rangeMin:"-10",rangeMax:"10",color:KhanColors.BLUE,strokeDasharray:"",strokeWidth:2};
1521
1522
 
@@ -1539,96 +1540,104 @@ const{getDependencies: getDependencies$1}=Dependencies;class RectangleEditor ext
1539
1540
 
1540
1541
  const{getDependencies}=Dependencies;const{unescapeMathMode}=Util;class InteractionEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({usedVarSubscripts:this._getAllVarSubscripts(nextProps.elements),usedFunctionNames:this._getAllFunctionNames(nextProps.elements)});}_getAllVarSubscripts(elements){return _.map(_.where(elements,{type:"movable-point"}),element=>element.options.varSubscript).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.startSubscript)).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.endSubscript))}_getAllFunctionNames(elements){return _.map(_.where(elements,{type:"function"}),element=>element.options.funcName)}render(){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-interaction-editor",children:[jsxRuntimeExports.jsxs(ElementContainer,{title:"Grid settings",children:[jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["canvas","graph"],box:this.props.graph.box,labels:this.props.graph.labels,range:this.props.graph.range,step:this.props.graph.tickStep,gridStep:this.props.graph.gridStep,markings:this.props.graph.markings,onChange:this._updateGraphProps}),jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:this.props.graph.valid!==true&&jsxRuntimeExports.jsx("div",{children:this.props.graph.valid})})]}),_.map(this.props.elements,function(element,n){if(element.type==="movable-point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable point"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.varSubscript+"}, y_{"+element.options.varSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovablePointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="movable-line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable line"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.startSubscript+"}, y_{"+element.options.startSubscript+"})"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.endSubscript+"}, y_{"+element.options.endSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovableLineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Point"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(PointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Line"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.startX+", "+element.options.startY+")"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.endX+", "+element.options.endY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(LineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="function"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Function"," ",jsxRuntimeExports.jsx(TeX,{children:element.options.funcName+"(x) = "+element.options.value})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(FunctionEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="parametric"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsx("span",{children:"Parametric"}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(ParametricEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="label"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Label"," ",jsxRuntimeExports.jsx(TeX,{children:unescapeMathMode(element.options.label)})," "]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(LabelEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="rectangle"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Rectangle"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})," — ",jsxRuntimeExports.jsx(TeX,{children:element.options.width+" \\times "+element.options.height})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(RectangleEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}},this),jsxRuntimeExports.jsx("div",{className:"perseus-widget-interaction-editor-select-element",children:jsxRuntimeExports.jsxs("select",{onChange:this._addNewElement,children:[jsxRuntimeExports.jsxs("option",{value:"",children:["Add an element","…"]}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"point",children:"Point"}),jsxRuntimeExports.jsx("option",{value:"line",children:"Line segment"}),jsxRuntimeExports.jsx("option",{value:"function",children:"Function plot"}),jsxRuntimeExports.jsx("option",{value:"parametric",children:"Parametric plot"}),jsxRuntimeExports.jsx("option",{value:"label",children:"Label"}),jsxRuntimeExports.jsx("option",{value:"rectangle",children:"Rectangle"}),jsxRuntimeExports.jsx("option",{value:"movable-point",children:"★ Movable point"}),jsxRuntimeExports.jsx("option",{value:"movable-line",children:"★ Movable line segment"})]})})]})}constructor(...args){super(...args),this.state={usedVarSubscripts:this._getAllVarSubscripts(this.props.elements),usedFunctionNames:this._getAllFunctionNames(this.props.elements)},this._updateGraphProps=newProps=>{this.change({graph:_.extend(_.omit(newProps,"step"),{tickStep:newProps.step})});},this._addNewElement=e=>{const elementType=e.target.value;if(elementType===""){return}e.target.value="";const newElement={type:elementType,key:elementType+"-"+(Math.random()*0xffffff<<0).toString(16),options:elementType==="point"?_.clone(PointEditor.defaultProps):elementType==="line"?_.clone(LineEditor.defaultProps):elementType==="movable-point"?_.clone(MovablePointEditor.defaultProps):elementType==="movable-line"?_.clone(MovableLineEditor.defaultProps):elementType==="function"?_.clone(FunctionEditor.defaultProps):elementType==="parametric"?_.clone(ParametricEditor.defaultProps):elementType==="label"?_.clone(LabelEditor.defaultProps):elementType==="rectangle"?_.clone(RectangleEditor.defaultProps):{}};let nextSubscript;if(elementType==="movable-point"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.varSubscript=nextSubscript;}else if(elementType==="movable-line"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.startSubscript=nextSubscript;newElement.options.endSubscript=nextSubscript+1;}else if(elementType==="function"){const nextLetter=String.fromCharCode(_.max([_.max(_.map(this.state.usedFunctionNames,function(c){return c.charCodeAt(0)})),"e".charCodeAt(0)])+1);newElement.options.funcName=nextLetter;}this.change({elements:this.props.elements.concat(newElement)});},this._deleteElement=index=>{const element=this.props.elements[index];this.change({elements:_.without(this.props.elements,element)});},this._moveElementUp=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index-1,0,element);this.change({elements:newElements});},this._moveElementDown=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index+1,0,element);this.change({elements:newElements});},this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}InteractionEditor.widgetName="interaction";InteractionEditor.defaultProps=interactionLogic.defaultWidgetOptions;
1541
1542
 
1543
+ var styles$I = {"singleSelectShort":"perseus_wAZzFxEx","row":"perseus_6FquBkGo"};
1544
+
1545
+ const LabeledRow=props=>{const{children,label,labelSide="left",style}=props;return jsxRuntimeExports.jsx("label",{className:css(styles$H.label),children:jsxRuntimeExports.jsxs(View,{style:[styles$H.row,style],children:[labelSide==="start"||jsxRuntimeExports.jsx(LabelSmall,{style:styles$H.spaceEnd,children:label}),children,labelSide==="end"&&jsxRuntimeExports.jsx(LabelSmall,{style:styles$H.spaceStart,children:label})]})})};const styles$H=StyleSheet.create({label:{width:"fit-content"},row:{flexDirection:"row",marginTop:spacing.xSmall_8,alignItems:"center",width:"fit-content"},spaceStart:{marginInlineStart:spacing.xSmall_8},spaceEnd:{marginInlineEnd:spacing.xSmall_8}});
1546
+
1547
+ const{InfoTip: InfoTip$h}=components;function AngleAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$I.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:newValue=>{if(graph?.type==="angle"){invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,showAngles:newValue},graph:{...graph,showAngles:newValue}});}}}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$I.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Allow reflex angles"}),checked:!!correct?.allowReflexAngles,onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);invariant(graph?.type==="angle",`Expected graph type to be angle, but got ${graph?.type}`);const update={allowReflexAngles:newValue};onChange({correct:{...correct,...update},graph:{...graph,...update}});}}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Allow students to be able to create reflex angles."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,match:newValue}});},placeholder:"",className:styles$I.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"})]}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position."})})]})]})}
1548
+
1542
1549
  const UNLIMITED="unlimited";const parsePointCount=points=>{const parsed=parseInt(points,10);if(isNaN(parsed)){return UNLIMITED}return parsed===0?UNLIMITED:parsed};
1543
1550
 
1544
- const GraphPointsCountSelector=({numPoints=1,onChange})=>{return jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${numPoints}`,onChange:newValue=>{onChange(parsePointCount(newValue));},placeholder:"",style:styles$K.singleSelectShort,children:[...[...Array(7).keys()].map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} point${n>1?"s":""}`},n)),jsxRuntimeExports.jsx(OptionItem,{value:UNLIMITED,label:"unlimited"},"unlimited")]})};const styles$K=StyleSheet.create({singleSelectShort:{height:26}});
1551
+ const GraphPointsCountSelector=({correct,graph,onChange})=>{return jsxRuntimeExports.jsx(LabeledRow,{label:"Number of Points:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${correct.numPoints??1}`,onChange:newValue=>{const points=parsePointCount(newValue);onChange({correct:{type:"point",numPoints:points},graph:{type:"point",numPoints:points}});},placeholder:"",className:styles$I.singleSelectShort,children:[...[...Array(7).keys()].map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} point${n>1?"s":""}`},n)),jsxRuntimeExports.jsx(OptionItem,{value:UNLIMITED,label:"unlimited"},"unlimited")]})})};
1545
1552
 
1546
- const GraphTypeSelector=props=>{return jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:props.graphType,onChange:props.onChange,placeholder:"Select an answer type",style:styles$J.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"none",label:"None"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear",label:"Linear function"}),jsxRuntimeExports.jsx(OptionItem,{value:"quadratic",label:"Quadratic function"}),jsxRuntimeExports.jsx(OptionItem,{value:"sinusoid",label:"Sinusoid function"}),jsxRuntimeExports.jsx(OptionItem,{value:"circle",label:"Circle"}),jsxRuntimeExports.jsx(OptionItem,{value:"point",label:"Point(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear-system",label:"Linear System"}),jsxRuntimeExports.jsx(OptionItem,{value:"polygon",label:"Polygon"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"Line Segment(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"Ray"}),jsxRuntimeExports.jsx(OptionItem,{value:"angle",label:"Angle"})]})};const styles$J=StyleSheet.create({singleSelectShort:{height:26}});
1553
+ const GraphTypeSelector=props=>{return jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:props.graphType,onChange:props.onChange,placeholder:"Select an answer type",style:styles$G.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"none",label:"None"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear",label:"Linear function"}),jsxRuntimeExports.jsx(OptionItem,{value:"quadratic",label:"Quadratic function"}),jsxRuntimeExports.jsx(OptionItem,{value:"sinusoid",label:"Sinusoid function"}),jsxRuntimeExports.jsx(OptionItem,{value:"circle",label:"Circle"}),jsxRuntimeExports.jsx(OptionItem,{value:"point",label:"Point(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"linear-system",label:"Linear System"}),jsxRuntimeExports.jsx(OptionItem,{value:"polygon",label:"Polygon"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"Line Segment(s)"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"Ray"}),jsxRuntimeExports.jsx(OptionItem,{value:"angle",label:"Angle"})]})};const styles$G=StyleSheet.create({singleSelectShort:{height:26}});
1547
1554
 
1548
- function Heading({title,isOpen,isCollapsible,onToggle}){return jsxRuntimeExports.jsx(Clickable,{style:[styles$I.container,!isCollapsible&&styles$I.notClickable],disabled:!isCollapsible,onClick:()=>isCollapsible&&onToggle?.(!isOpen),children:()=>jsxRuntimeExports.jsxs(View,{style:styles$I.heading,children:[jsxRuntimeExports.jsx(LabelLarge,{style:{fontSize:14,fontWeight:600},children:title}),isCollapsible&&jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:isOpen})]})})}const styles$I=StyleSheet.create({container:{marginTop:spacing.small_12,marginInline:-10,backgroundColor:color.offBlack8,padding:spacing.xSmall_8,width:"calc(100% + 20px)"},heading:{flexDirection:"row",justifyContent:"space-between",userSelect:"none"},notClickable:{color:"inherit",cursor:"default"}});
1555
+ function Heading({title,isOpen,isCollapsible,onToggle}){return jsxRuntimeExports.jsx(Clickable,{style:[styles$F.container,!isCollapsible&&styles$F.notClickable],disabled:!isCollapsible,onClick:()=>isCollapsible&&onToggle?.(!isOpen),children:()=>jsxRuntimeExports.jsxs(View,{style:styles$F.heading,children:[jsxRuntimeExports.jsx(LabelLarge,{style:{fontSize:14,fontWeight:600},children:title}),isCollapsible&&jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:isOpen})]})})}const styles$F=StyleSheet.create({container:{marginTop:spacing.small_12,marginInline:-10,backgroundColor:color.offBlack8,padding:spacing.xSmall_8,width:"calc(100% + 20px)"},heading:{flexDirection:"row",justifyContent:"space-between",userSelect:"none"},notClickable:{color:"inherit",cursor:"default"}});
1549
1556
 
1550
1557
  function InteractiveGraphCorrectAnswer(props){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Correct Answer",isOpen:true,isCollapsible:false}),jsxRuntimeExports.jsxs(View,{id:props.id,children:[jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6,color:color.offBlack64},children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."}),jsxRuntimeExports.jsx(BodyMonospace,{style:{fontSize:12,backgroundColor:"#eee",paddingInline:spacing.xxSmall_6,borderColor:"#ccc",borderStyle:"solid",borderWidth:1},children:props.equationString})]}),props.children]})]})}
1551
1558
 
1552
- function InteractiveGraphDescription(props){const{ariaLabelValue,ariaDescriptionValue,onChange}=props;const[isOpen,setIsOpen]=React.useState(true);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Description",isCollapsible:true,isOpen:isOpen,onToggle:setIsOpen}),isOpen&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:styles$H.caption,children:"Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",children:["Title",jsxRuntimeExports.jsx(TextField,{value:ariaLabelValue,onChange:newValue=>onChange({fullGraphAriaLabel:newValue||undefined}),style:styles$H.spaceAbove})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",children:["Description",jsxRuntimeExports.jsx(TextArea,{rows:8,resizeType:"vertical",value:ariaDescriptionValue,onChange:newValue=>onChange({fullGraphAriaDescription:newValue||undefined}),style:styles$H.spaceAbove})]})]})]})}const styles$H=StyleSheet.create({caption:{color:color.offBlack64,paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},spaceAbove:{marginTop:spacing.xxxSmall_4}});
1559
+ const AutoResizingTextArea=props=>{const textAreaRef=React.useRef(null);React.useEffect(()=>{const textArea=textAreaRef.current;if(textArea){textArea.style.height="42px";textArea.style.height=`${textArea.scrollHeight}px`;}},[props.value]);return jsxRuntimeExports.jsx(TextArea,{...props,ref:textAreaRef,resizeType:"none",style:{overflow:"hidden",...props.style}})};
1553
1560
 
1554
- const LabeledRow=props=>{const{children,label,labelSide="left",style}=props;return jsxRuntimeExports.jsx("label",{className:css(styles$G.label),children:jsxRuntimeExports.jsxs(View,{style:[styles$G.row,style],children:[labelSide==="start"||jsxRuntimeExports.jsx(LabelSmall,{style:styles$G.spaceEnd,children:label}),children,labelSide==="end"&&jsxRuntimeExports.jsx(LabelSmall,{style:styles$G.spaceStart,children:label})]})})};const styles$G=StyleSheet.create({label:{width:"fit-content"},row:{flexDirection:"row",marginTop:spacing.xSmall_8,alignItems:"center",width:"fit-content"},spaceStart:{marginInlineStart:spacing.xSmall_8},spaceEnd:{marginInlineEnd:spacing.xSmall_8}});
1561
+ function InteractiveGraphDescription(props){const{ariaLabelValue,ariaDescriptionValue,onChange}=props;const[isOpen,setIsOpen]=React.useState(true);const uniqueId=React.useId();const descriptionTextAreaId=`${uniqueId}-description-textarea`;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Description",isCollapsible:true,isOpen:isOpen,onToggle:setIsOpen}),isOpen&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:styles$E.caption,children:"Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",children:["Title",jsxRuntimeExports.jsx(TextField,{value:ariaLabelValue,onChange:newValue=>onChange({fullGraphAriaLabel:newValue||undefined}),style:styles$E.spaceAbove})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:descriptionTextAreaId,children:"Description"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:descriptionTextAreaId,value:ariaDescriptionValue,onChange:newValue=>onChange({fullGraphAriaDescription:newValue||undefined})})]})]})}const styles$E=StyleSheet.create({caption:{color:color.offBlack64,paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},spaceAbove:{marginTop:spacing.xxxSmall_4}});
1555
1562
 
1556
- const{ButtonGroup: ButtonGroup$1,InfoTip: InfoTip$g,RangeInput: RangeInput$4}=components;const defaultBackgroundImage={url:null,width:0,height:0};function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}class InteractiveGraphSettings extends React.Component{static stateFromProps(props){return {labelsTextbox:props.labels,labelLocation:props.labelLocation,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:{...props.backgroundImage}}}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.labelLocation,nextProps.labelLocation)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(InteractiveGraphSettings.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Common Graph Settings",isOpen:this.state.isExpanded,isCollapsible:true,onToggle:()=>this.setState({isExpanded:!this.state.isExpanded})}),this.state.isExpanded&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Label Location",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.labelLocation,allowEmpty:false,buttons:[{value:"onAxis",content:"On Axis"},{value:"alongEdge",content:"Along Graph Edge"}],onChange:this.change("labelLocation")})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelXRef,onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelYRef,onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals),allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals),allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Tick Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.stepTextbox,onChange:this.changeStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Grid Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.gridStepTextbox,onChange:this.changeGridStep,allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Snap Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.snapStepTextbox,onChange:this.changeSnapStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",onClick:()=>{this.changeStepsBasedOnRange();},children:"Auto-adjust steps"}),jsxRuntimeExports.jsxs(InfoTip$g,{children:[jsxRuntimeExports.jsx("p",{children:'Use the "Auto-adjust" steps button to update the tick step, grid step, and snap step to values that are valid for the current range.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("p",{children:"This is useful when the range is changed, and the graph errors due to the step sizes being too large or too small."})]})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Markings:",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.markings,allowEmpty:false,buttons:[{value:"axes",content:"Axes"},{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Background image URL:",style:styles$F.resetSpaceTop,children:[jsxRuntimeExports.jsx("input",{type:"text",className:css(styles$F.backgroundUrlInput),ref:this.bgUrlRef,value:this.state.backgroundImage.url||"",onChange:e=>{const image={...this.props.backgroundImage};image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),jsxRuntimeExports.jsxs(View,{style:styles$F.protractorSection,children:[jsxRuntimeExports.jsx(View,{style:styles$F.checkboxRow,children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});},style:styles$F.resetSpaceTop})}),this.props.showProtractor&&jsxRuntimeExports.jsx(Banner,{layout:"floating",text:"The protractor is not accessible. Please consider an alternate approach.",kind:"warning"})]})]})]})}constructor(props){super(props),this._isMounted=false,this.bgUrlRef=React.createRef(),this.labelXRef=React.createRef(),this.labelYRef=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.changeBackgroundUrl=e=>{if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image={...this.props.backgroundImage};image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=this.bgUrlRef.current?.value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}},this.renderLabelChoices=choices=>{return choices.map(nameAndValue=>jsxRuntimeExports.jsx("option",{value:nameAndValue[1],children:nameAndValue[0]},nameAndValue[1]))},this.validRange=range=>{const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true},this.validateStepValue=settings=>{const{step,range,name,minTicks,maxTicks}=settings;const nSteps=numSteps(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true},this.validSnapStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})},this.validGridStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})},this.validStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})},this.validBackgroundImageSize=image=>{if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true},this.validateGraphSettings=(range,step,gridStep,snapStep,image)=>{const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true},this.changeLabel=(i,e)=>{const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);},this.changeRange=(i,values)=>{const ranges=this.state.rangeTextbox.slice();ranges[i]=values;this.setState({rangeTextbox:ranges},this.changeGraph);},this.changeStepsBasedOnRange=()=>{const ranges=this.state.rangeTextbox.slice();const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scaleX=Util.scaleFromExtent(ranges[0],this.props.box[0]);if(this.validRange(ranges[0])===true){step[0]=Util.tickStepFromExtent(ranges[0],this.props.box[0]);const gridStepValue=Util.gridStepFromTickStep(step[0],scaleX);if(gridStepValue){gridStep[0]=gridStepValue;}snapStep[0]=gridStep[0]/2;}const scaleY=Util.scaleFromExtent(ranges[1],this.props.box[1]);if(this.validRange(ranges[1])===true){step[1]=Util.tickStepFromExtent(ranges[1],this.props.box[1]);const gridStepValue=Util.gridStepFromTickStep(step[1],scaleY);if(gridStepValue){gridStep[1]=gridStepValue;}snapStep[1]=gridStep[1]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);},this.changeStep=step=>{this.setState({stepTextbox:step},this.changeGraph);},this.changeSnapStep=snapStep=>{this.setState({snapStepTextbox:snapStep},this.changeGraph);},this.changeGridStep=gridStep=>{this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);},this.changeGraph=()=>{const labels=this.state.labelsTextbox;const labelLocation=this.state.labelLocation;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,labelLocation:labelLocation,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}};this.state={isExpanded:true,...InteractiveGraphSettings.stateFromProps(props)};}}InteractiveGraphSettings.defaultProps={box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage,markings:"graph",showProtractor:false,showTooltips:false};const styles$F=StyleSheet.create({resetSpaceTop:{marginTop:0},backgroundUrlInput:{border:`1px solid ${color.offBlack32}`,borderRadius:spacing.xxxSmall_4,padding:spacing.xxxSmall_4},checkboxRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:spacing.xSmall_8},protractorSection:{marginTop:spacing.xSmall_8,borderTop:`1px solid ${color.offBlack16}`,paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${color.offBlack16}`}});
1563
+ const{ButtonGroup: ButtonGroup$1,InfoTip: InfoTip$g,RangeInput: RangeInput$4}=components;const defaultBackgroundImage={url:null,width:0,height:0};function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}class InteractiveGraphSettings extends React.Component{static stateFromProps(props){return {labelsTextbox:props.labels,labelLocation:props.labelLocation,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:{...props.backgroundImage}}}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.labelLocation,nextProps.labelLocation)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(InteractiveGraphSettings.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Common Graph Settings",isOpen:this.state.isExpanded,isCollapsible:true,onToggle:()=>this.setState({isExpanded:!this.state.isExpanded})}),this.state.isExpanded&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Label Location",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.labelLocation,allowEmpty:false,buttons:[{value:"onAxis",content:"On Axis"},{value:"alongEdge",content:"Along Graph Edge"}],onChange:this.change("labelLocation")})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelXRef,onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelYRef,onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals),allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals),allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Tick Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.stepTextbox,onChange:this.changeStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Grid Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.gridStepTextbox,onChange:this.changeGridStep,allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Snap Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.snapStepTextbox,onChange:this.changeSnapStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",onClick:()=>{this.changeStepsBasedOnRange();},children:"Auto-adjust steps"}),jsxRuntimeExports.jsxs(InfoTip$g,{children:[jsxRuntimeExports.jsx("p",{children:'Use the "Auto-adjust" steps button to update the tick step, grid step, and snap step to values that are valid for the current range.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("p",{children:"This is useful when the range is changed, and the graph errors due to the step sizes being too large or too small."})]})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Markings:",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.markings,allowEmpty:false,buttons:[{value:"axes",content:"Axes"},{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Background image URL:",style:styles$D.resetSpaceTop,children:[jsxRuntimeExports.jsx("input",{type:"text",className:css(styles$D.backgroundUrlInput),ref:this.bgUrlRef,value:this.state.backgroundImage.url||"",onChange:e=>{const image={...this.props.backgroundImage};image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),jsxRuntimeExports.jsxs(View,{style:styles$D.protractorSection,children:[jsxRuntimeExports.jsx(View,{style:styles$D.checkboxRow,children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});},style:styles$D.resetSpaceTop})}),this.props.showProtractor&&jsxRuntimeExports.jsx(Banner,{layout:"floating",text:"The protractor is not accessible. Please consider an alternate approach.",kind:"warning"})]})]})]})}constructor(props){super(props),this._isMounted=false,this.bgUrlRef=React.createRef(),this.labelXRef=React.createRef(),this.labelYRef=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.changeBackgroundUrl=e=>{if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image={...this.props.backgroundImage};image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=this.bgUrlRef.current?.value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}},this.renderLabelChoices=choices=>{return choices.map(nameAndValue=>jsxRuntimeExports.jsx("option",{value:nameAndValue[1],children:nameAndValue[0]},nameAndValue[1]))},this.validRange=range=>{const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true},this.validateStepValue=settings=>{const{step,range,name,minTicks,maxTicks}=settings;const nSteps=numSteps(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true},this.validSnapStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})},this.validGridStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})},this.validStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})},this.validBackgroundImageSize=image=>{if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true},this.validateGraphSettings=(range,step,gridStep,snapStep,image)=>{const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true},this.changeLabel=(i,e)=>{const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);},this.changeRange=(i,values)=>{const ranges=this.state.rangeTextbox.slice();ranges[i]=values;this.setState({rangeTextbox:ranges},this.changeGraph);},this.changeStepsBasedOnRange=()=>{const ranges=this.state.rangeTextbox.slice();const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scaleX=Util.scaleFromExtent(ranges[0],this.props.box[0]);if(this.validRange(ranges[0])===true){step[0]=Util.tickStepFromExtent(ranges[0],this.props.box[0]);const gridStepValue=Util.gridStepFromTickStep(step[0],scaleX);if(gridStepValue){gridStep[0]=gridStepValue;}snapStep[0]=gridStep[0]/2;}const scaleY=Util.scaleFromExtent(ranges[1],this.props.box[1]);if(this.validRange(ranges[1])===true){step[1]=Util.tickStepFromExtent(ranges[1],this.props.box[1]);const gridStepValue=Util.gridStepFromTickStep(step[1],scaleY);if(gridStepValue){gridStep[1]=gridStepValue;}snapStep[1]=gridStep[1]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);},this.changeStep=step=>{this.setState({stepTextbox:step},this.changeGraph);},this.changeSnapStep=snapStep=>{this.setState({snapStepTextbox:snapStep},this.changeGraph);},this.changeGridStep=gridStep=>{this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);},this.changeGraph=()=>{const labels=this.state.labelsTextbox;const labelLocation=this.state.labelLocation;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,labelLocation:labelLocation,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}};this.state={isExpanded:true,...InteractiveGraphSettings.stateFromProps(props)};}}InteractiveGraphSettings.defaultProps={box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage,markings:"graph",showProtractor:false,showTooltips:false};const styles$D=StyleSheet.create({resetSpaceTop:{marginTop:0},backgroundUrlInput:{border:`1px solid ${color.offBlack32}`,borderRadius:spacing.xxxSmall_4,padding:spacing.xxxSmall_4},checkboxRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:spacing.xSmall_8},protractorSection:{marginTop:spacing.xSmall_8,borderTop:`1px solid ${color.offBlack16}`,paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${color.offBlack16}`}});
1557
1564
 
1558
- const{InfoTip: InfoTip$f}=components;const StyledUl=addStyle("ul");function getAccessibilityAttributes(graphId){const elementArias=[];const container=document.getElementById(graphId);if(!container){return elementArias}container.querySelectorAll("*").forEach(element=>{const elementAttributes=[];const ariaLabel=element.getAttribute("aria-label");const ariaDescribedby=element.getAttribute("aria-describedby");if(ariaLabel){elementAttributes.unshift({name:"label",value:ariaLabel});}if(ariaDescribedby){const descriptions=ariaDescribedby.split(/ +/);for(const description of descriptions){const descriptionString=document.getElementById(description)?.textContent;if(descriptionString){elementAttributes.push({name:"description",value:descriptionString});}}}if(elementAttributes.length>0){elementArias.push({roleOrTag:element.getAttribute("role")||element.tagName.toLowerCase(),className:element.classList[element.classList.length-1]||"",attributes:elementAttributes});}});return elementArias}function SRTree(props){const{elementArias,showTags}=props;return jsxRuntimeExports.jsx("ol",{style:{listStyle:"revert",marginLeft:8},children:elementArias.map((aria,index)=>jsxRuntimeExports.jsxs("li",{children:[showTags&&jsxRuntimeExports.jsx(Pill,{size:"small",kind:"success",style:styles$E.smallSpaceRight,children:aria.roleOrTag}),aria.className,jsxRuntimeExports.jsx(StyledUl,{style:styles$E.indentListLeft,children:aria.attributes.map((value,index)=>jsxRuntimeExports.jsxs("li",{children:[jsxRuntimeExports.jsx(Pill,{size:"small",kind:value.name==="label"?"info":"neutral",style:styles$E.smallSpaceRight,children:value.name}),value.value]},index))})]},index))})}function InteractiveGraphSRTree({graphId,correct,fullGraphAriaLabel,fullGraphAriaDescription,lockedFigures}){const[isExpanded,setIsExpanded]=React.useState(true);const[showTags,setShowTags]=React.useState(false);const[elementArias,setElementArias]=React.useState([]);const switchId=React.useId();React.useEffect(()=>{setElementArias(getAccessibilityAttributes(graphId));},[correct,fullGraphAriaLabel,fullGraphAriaDescription,graphId,lockedFigures]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Screen reader tree",isOpen:isExpanded,onToggle:setIsExpanded,isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:[styles$E.row,styles$E.tagSwitch],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:showTags,onChange:setShowTags}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelSmall,{tag:"label",htmlFor:switchId,children:"Show HTML roles/tags"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(InfoTip$f,{children:'This screen reader tree shows the ARIA labels and descriptions for elements within the "correct answer" Interactive Graph widget displayed above.'})]}),jsxRuntimeExports.jsx(SRTree,{elementArias:elementArias,showTags:showTags})]})]})}const styles$E=StyleSheet.create({smallSpaceRight:{marginRight:spacing.xxSmall_6},indentListLeft:{listStyle:"revert",marginLeft:spacing.small_12},tagSwitch:{marginTop:spacing.xSmall_8,marginBottom:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"}});
1565
+ const{InfoTip: InfoTip$f}=components;const StyledUl=addStyle("ul");function getAccessibilityAttributes(graphId){const elementArias=[];const container=document.getElementById(graphId);if(!container){return elementArias}container.querySelectorAll("*").forEach(element=>{const elementAttributes=[];const ariaLabel=element.getAttribute("aria-label");const ariaDescribedby=element.getAttribute("aria-describedby");if(ariaLabel){elementAttributes.unshift({name:"label",value:ariaLabel});}if(ariaDescribedby){const descriptions=ariaDescribedby.split(/ +/);for(const description of descriptions){const descriptionString=document.getElementById(description)?.textContent;if(descriptionString){elementAttributes.push({name:"description",value:descriptionString});}}}if(elementAttributes.length>0){elementArias.push({roleOrTag:element.getAttribute("role")||element.tagName.toLowerCase(),className:element.classList[element.classList.length-1]||"",attributes:elementAttributes});}});return elementArias}function SRTree(props){const{elementArias,showTags}=props;return jsxRuntimeExports.jsx("ol",{style:{listStyle:"revert",marginLeft:8},children:elementArias.map((aria,index)=>jsxRuntimeExports.jsxs("li",{children:[showTags&&jsxRuntimeExports.jsx(Pill,{size:"small",kind:"success",style:styles$C.smallSpaceRight,children:aria.roleOrTag}),aria.className,jsxRuntimeExports.jsx(StyledUl,{style:styles$C.indentListLeft,children:aria.attributes.map((value,index)=>jsxRuntimeExports.jsxs("li",{children:[jsxRuntimeExports.jsx(Pill,{size:"small",kind:value.name==="label"?"info":"neutral",style:styles$C.smallSpaceRight,children:value.name}),value.value]},index))})]},index))})}function InteractiveGraphSRTree({graphId,correct,fullGraphAriaLabel,fullGraphAriaDescription,lockedFigures}){const[isExpanded,setIsExpanded]=React.useState(true);const[showTags,setShowTags]=React.useState(false);const[elementArias,setElementArias]=React.useState([]);const switchId=React.useId();React.useEffect(()=>{setElementArias(getAccessibilityAttributes(graphId));},[correct,fullGraphAriaLabel,fullGraphAriaDescription,graphId,lockedFigures]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Screen reader tree",isOpen:isExpanded,onToggle:setIsExpanded,isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:[styles$C.row,styles$C.tagSwitch],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:showTags,onChange:setShowTags}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelSmall,{tag:"label",htmlFor:switchId,children:"Show HTML roles/tags"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(InfoTip$f,{children:'This screen reader tree shows the ARIA labels and descriptions for elements within the "correct answer" Interactive Graph widget displayed above.'})]}),jsxRuntimeExports.jsx(SRTree,{elementArias:elementArias,showTags:showTags})]})]})}const styles$C=StyleSheet.create({smallSpaceRight:{marginRight:spacing.xxSmall_6},indentListLeft:{listStyle:"revert",marginLeft:spacing.small_12},tagSwitch:{marginTop:spacing.xSmall_8,marginBottom:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"}});
1559
1566
 
1560
- const SegmentCountSelector=({numSegments=1,onChange})=>jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${numSegments}`,placeholder:"",onChange:newValue=>{const num=+newValue;onChange(num);},style:styles$D.singleSelectShort,children:_.range(1,7).map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} segment${n>1?"s":""}`},n))},"segment-select");const styles$D=StyleSheet.create({singleSelectShort:{height:26}});
1567
+ const{InfoTip: InfoTip$e}=components;const POLYGON_SIDES=_.map(_.range(3,13),function(value){return jsxRuntimeExports.jsx(OptionItem,{value:`${value}`,label:`${value} sides`},`polygon-sides-${value}`)});function PolygonAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Number of sides:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:correct?.numSides?`${correct.numSides}`:"3",placeholder:"",onChange:newValue=>{invariant(graph?.type==="polygon");const updates={numSides:parsePointCount(newValue),coords:undefined,startCoords:undefined,snapTo:"grid"};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$I.singleSelectShort,children:[...POLYGON_SIDES,jsxRuntimeExports.jsx(OptionItem,{value:"unlimited",label:"unlimited sides"},"unlimited")]},"polygon-select")}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Snap to:",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct?.snapTo||"grid",placeholder:"",onChange:newValue=>{invariant(correct.type==="polygon",`Expected correct answer type to be polygon, but got ${correct.type}`);invariant(graph?.type==="polygon",`Expected graph type to be polygon, but got ${graph?.type}`);const updates={snapTo:newValue,coords:null};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$I.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"grid",label:"grid"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"angles",label:"interior angles"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"sides",label:"side measures"})]}),jsxRuntimeExports.jsxs(InfoTip$e,{children:[jsxRuntimeExports.jsx("p",{children:"These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."}),jsxRuntimeExports.jsx("p",{children:"The interior angle and side measure options guide the points to the nearest whole angle or side measure respectively."})]})]}),jsxRuntimeExports.jsxs(View,{className:styles$I.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:()=>{if(graph?.type==="polygon"){invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);onChange({correct:{...correct,showAngles:!correct.showAngles},graph:{...graph,showAngles:!graph.showAngles}});}}}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$I.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show side measures"}),checked:!!correct?.showSides,onChange:()=>{if(graph?.type==="polygon"&&correct.type==="polygon"){onChange({correct:{...correct,showSides:!correct.showSides},graph:{...graph,showSides:!graph.showSides}});}}}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsx("p",{children:"Displays the side lengths."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);const updatedCorrect={...correct,match:newValue};onChange({correct:updatedCorrect});},placeholder:"",className:styles$I.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"approx",label:"be approximately congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"similar",label:"be similar"})]}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsxs("ul",{children:[jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Match Exactly:"})," Match exactly in size, orientation, and location on the grid even if it is not shown in the background."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Congruent:"})," Be congruent in size and shape, but can be located anywhere on the grid."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Approximately Congruent:"})," Be exactly similar, and congruent in size and shape to within 0.1 units, but can be located anywhere on the grid."," ",jsxRuntimeExports.jsx("em",{children:"Use this with snapping to angle measure."})]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Similar:"})," Be similar with matching interior angles, and side measures that are matching or a multiple of the correct side measures. The figure can be located anywhere on the grid."]})})]})})]})]})}
1561
1568
 
1562
- const LockedFigureSelect=props=>{const{id,onChange}=props;const figureTypes=["point","line","vector","ellipse","polygon","function","label"];return jsxRuntimeExports.jsx(View,{style:styles$C.container,children:jsxRuntimeExports.jsx(ActionMenu,{menuText:"Add locked figure",style:styles$C.addElementSelect,children:figureTypes.map(figureType=>jsxRuntimeExports.jsx(ActionItem,{label:figureType,onClick:()=>onChange(figureType)},`${id}-${figureType}`))})})};const styles$C=StyleSheet.create({container:{marginTop:spacing.xSmall_8},addElementSelect:{backgroundColor:color.fadedBlue8,borderRadius:spacing.xxxSmall_4}});
1569
+ const SegmentCountSelector=({correct,graph,onChange})=>jsxRuntimeExports.jsx(LabeledRow,{label:"Number of segments:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${correct.numSegments??1}`,placeholder:"",onChange:newValue=>{const sides=+newValue;onChange({correct:{type:"segment",numSegments:sides,coords:null},graph:{type:"segment",numSegments:sides}});},className:styles$I.singleSelectShort,children:_.range(1,7).map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} segment${n>1?"s":""}`},n))},"segment-select")});
1570
+
1571
+ const LockedFigureSelect=props=>{const{id,onChange}=props;const figureTypes=["point","line","vector","ellipse","polygon","function","label"];return jsxRuntimeExports.jsx(View,{style:styles$B.container,children:jsxRuntimeExports.jsx(ActionMenu,{menuText:"Add locked figure",style:styles$B.addElementSelect,children:figureTypes.map(figureType=>jsxRuntimeExports.jsx(ActionItem,{label:figureType,onClick:()=>onChange(figureType)},`${id}-${figureType}`))})})};const styles$B=StyleSheet.create({container:{marginTop:spacing.xSmall_8},addElementSelect:{backgroundColor:color.fadedBlue8,borderRadius:spacing.xxxSmall_4}});
1563
1572
 
1564
1573
  const ScrolllessNumberTextField=props=>{const{value,onChange,...restOfProps}=props;const[focused,setFocused]=React.useState(false);const[wipValue,setWipValue]=React.useState("");const inputRef=React.useRef(null);React.useEffect(()=>{const ref=inputRef.current;const ignoreScroll=e=>{e.stopPropagation();};ref?.addEventListener("wheel",ignoreScroll);return ()=>{ref?.removeEventListener("wheel",ignoreScroll);}},[inputRef]);return jsxRuntimeExports.jsx(TextField,{...restOfProps,type:"number",value:focused?wipValue:value,onChange:newValue=>{setWipValue(newValue);onChange(newValue);},onFocus:e=>{setWipValue(value);setFocused(true);props.onFocus?.(e);},onBlur:e=>{setFocused(false);props.onBlur?.(e);},ref:inputRef})};
1565
1574
 
1566
- const{convertDegreesToRadians,convertRadiansToDegrees: convertRadiansToDegrees$1}=angles;const AngleInput=props=>{const{angle,onChange}=props;const[angleInput,setAngleInput]=React.useState(convertRadiansToDegrees$1(angle).toString());function handleAngleChange(newValue){setAngleInput(newValue);if(isNaN(+newValue)||newValue===""){return}onChange(convertDegreesToRadians(newValue));}return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$B.row,children:["angle (degrees)",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:angleInput,onChange:handleAngleChange,style:styles$B.textField}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6})]})};const styles$B=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
1575
+ const{convertDegreesToRadians,convertRadiansToDegrees: convertRadiansToDegrees$1}=angles;const AngleInput=props=>{const{angle,onChange}=props;const[angleInput,setAngleInput]=React.useState(convertRadiansToDegrees$1(angle).toString());function handleAngleChange(newValue){setAngleInput(newValue);if(isNaN(+newValue)||newValue===""){return}onChange(convertDegreesToRadians(newValue));}return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$A.row,children:["angle (degrees)",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:angleInput,onChange:handleAngleChange,style:styles$A.textField}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6})]})};const styles$A=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
1567
1576
 
1568
- const CoordinatePairInput=props=>{const{coord,labels,error,style,onChange}=props;const[coordState,setCoordState]=React.useState([coord[0].toString(),coord[1].toString()]);React.useEffect(()=>{setCoordState([coord[0].toString(),coord[1].toString()]);},[coord]);function handleCoordChange(newValue,coordIndex){const newCoordState=[...coordState];newCoordState[coordIndex]=newValue;setCoordState(newCoordState);if(isNaN(+newValue)||newValue===""){return}const newCoords=[...coord];newCoords[coordIndex]=+newValue;onChange(newCoords);}return jsxRuntimeExports.jsxs(View,{style:[styles$A.row,style],children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$A.row,children:[labels?labels[0]:"x coord",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coordState[0],onChange:newValue=>handleCoordChange(newValue,0),style:[styles$A.textField,error?styles$A.errorField:undefined]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$A.row,children:[labels?labels[1]:"y coord",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coordState[1],onChange:newValue=>handleCoordChange(newValue,1),style:[styles$A.textField,error?styles$A.errorField:undefined]})]})]})};const styles$A=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64},errorField:{borderColor:color.red,backgroundColor:color.fadedRed8}});
1577
+ const CoordinatePairInput=props=>{const{coord,labels,error,style,onChange}=props;const[coordState,setCoordState]=React.useState([coord[0].toString(),coord[1].toString()]);React.useEffect(()=>{setCoordState([coord[0].toString(),coord[1].toString()]);},[coord]);function handleCoordChange(newValue,coordIndex){const newCoordState=[...coordState];newCoordState[coordIndex]=newValue;setCoordState(newCoordState);if(isNaN(+newValue)||newValue===""){return}const newCoords=[...coord];newCoords[coordIndex]=+newValue;onChange(newCoords);}return jsxRuntimeExports.jsxs(View,{style:[styles$z.row,style],children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$z.row,children:[labels?labels[0]:"x coord",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coordState[0],onChange:newValue=>handleCoordChange(newValue,0),style:[styles$z.textField,error?styles$z.errorField:undefined]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$z.row,children:[labels?labels[1]:"y coord",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coordState[1],onChange:newValue=>handleCoordChange(newValue,1),style:[styles$z.textField,error?styles$z.errorField:undefined]})]})]})};const styles$z=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64},errorField:{borderColor:color.red,backgroundColor:color.fadedRed8}});
1569
1578
 
1570
- const ColorSwatch=props=>{const{color: color$1,filled=true,decorative=false}=props;return jsxRuntimeExports.jsx(View,{"aria-label":!decorative?`${color$1}, ${filled?"filled":"open"}`:undefined,style:[styles$z.colorSwatch,{border:`4px solid ${lockedFigureColors[color$1]}`,backgroundColor:filled?lockedFigureColors[color$1]:color.white}]})};const styles$z=StyleSheet.create({colorSwatch:{outline:`2px solid ${color.offWhite}`,borderRadius:"50%",width:spacing.large_24,height:spacing.large_24}});
1579
+ const ColorSwatch=props=>{const{color: color$1,filled=true,decorative=false}=props;return jsxRuntimeExports.jsx(View,{"aria-label":!decorative?`${color$1}, ${filled?"filled":"open"}`:undefined,style:[styles$y.colorSwatch,{border:`4px solid ${lockedFigureColors[color$1]}`,backgroundColor:filled?lockedFigureColors[color$1]:color.white}]})};const styles$y=StyleSheet.create({colorSwatch:{outline:`2px solid ${color.offWhite}`,borderRadius:"50%",width:spacing.large_24,height:spacing.large_24}});
1571
1580
 
1572
- const possibleColors=Object.keys(lockedFigureColors);const ColorSelect=props=>{const{selectedValue,style,onChange}=props;return jsxRuntimeExports.jsx(View,{style:[styles$y.row,style],children:jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$y.row,children:["color",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:selectedValue,onChange:onChange,placeholder:"",children:possibleColors.map(colorName=>jsxRuntimeExports.jsx(OptionItem,{value:colorName,label:colorName,leftAccessory:jsxRuntimeExports.jsx(ColorSwatch,{color:colorName,decorative:true})},colorName))})]})})};const styles$y=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:"auto"}});
1581
+ const possibleColors=Object.keys(lockedFigureColors);const ColorSelect=props=>{const{selectedValue,style,onChange}=props;return jsxRuntimeExports.jsx(View,{style:[styles$x.row,style],children:jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$x.row,children:["color",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:selectedValue,onChange:onChange,placeholder:"",children:possibleColors.map(colorName=>jsxRuntimeExports.jsx(OptionItem,{value:colorName,label:colorName,leftAccessory:jsxRuntimeExports.jsx(ColorSwatch,{color:colorName,decorative:true})},colorName))})]})})};const styles$x=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:"auto"}});
1573
1582
 
1574
- const EllipseSwatch=props=>{const{color,fillStyle,strokeStyle}=props;return jsxRuntimeExports.jsx(View,{"aria-label":`${color}, stroke ${strokeStyle}, fill ${fillStyle}`,style:[styles$x.container,{border:`4px ${strokeStyle} ${lockedFigureColors[color]}`}],children:jsxRuntimeExports.jsx(View,{style:[styles$x.innerCircle,{backgroundColor:lockedFigureColors[color],opacity:fillStyle==="white"?0:lockedFigureFillStyles[fillStyle]}]})})};const styles$x=StyleSheet.create({container:{outline:`2px solid ${color.offWhite}`,borderRadius:"50%",width:spacing.xLarge_32,height:spacing.large_24,backgroundColor:color.white,alignItems:"center",justifyContent:"center"},innerCircle:{width:28,height:20,borderRadius:"50%"}});
1583
+ const EllipseSwatch=props=>{const{color,fillStyle,strokeStyle}=props;return jsxRuntimeExports.jsx(View,{"aria-label":`${color}, stroke ${strokeStyle}, fill ${fillStyle}`,style:[styles$w.container,{border:`4px ${strokeStyle} ${lockedFigureColors[color]}`}],children:jsxRuntimeExports.jsx(View,{style:[styles$w.innerCircle,{backgroundColor:lockedFigureColors[color],opacity:fillStyle==="white"?0:lockedFigureFillStyles[fillStyle]}]})})};const styles$w=StyleSheet.create({container:{outline:`2px solid ${color.offWhite}`,borderRadius:"50%",width:spacing.xLarge_32,height:spacing.large_24,backgroundColor:color.white,alignItems:"center",justifyContent:"center"},innerCircle:{width:28,height:20,borderRadius:"50%"}});
1575
1584
 
1576
- const LineStrokeSelect=props=>{const{selectedValue,containerStyle,onChange}=props;return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$w.lineStrokeSelect,containerStyle],children:["stroke",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:selectedValue,onChange:onChange,placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"solid",label:"solid"}),jsxRuntimeExports.jsx(OptionItem,{value:"dashed",label:"dashed"})]})]})};const styles$w=StyleSheet.create({lineStrokeSelect:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0}});
1585
+ const LineStrokeSelect=props=>{const{selectedValue,containerStyle,onChange}=props;return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$v.lineStrokeSelect,containerStyle],children:["stroke",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:selectedValue,onChange:onChange,placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"solid",label:"solid"}),jsxRuntimeExports.jsx(OptionItem,{value:"dashed",label:"dashed"})]})]})};const styles$v=StyleSheet.create({lineStrokeSelect:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0}});
1577
1586
 
1578
1587
  const LineWeightSelect=props=>{const{selectedValue,containerStyle,onChange}=props;return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},containerStyle],children:["weight",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:selectedValue,onChange:value=>onChange(value),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"thin",label:"thin"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"thick",label:"thick"})]})]})};
1579
1588
 
1580
- const{InfoTip: InfoTip$e}=components;function LockedFigureAria(props){const{ariaLabel,getPrepopulatedAriaLabel,onChangeProps}=props;const id=React.useId();const ariaLabelId=`aria-label-${id}`;const[loading,setLoading]=React.useState(false);return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:styles$v.row,children:[jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:ariaLabelId,children:"Aria label"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(InfoTip$e,{children:["Aria label is used by screen readers to describe content to users who may be visually impaired. ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader."]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(LabelXSmall,{style:styles$v.caption,children:"The figure is hidden from screen readers if this field is left blank."}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextArea,{id:ariaLabelId,value:loading?"Loading...":ariaLabel??"",onChange:newValue=>{onChangeProps({ariaLabel:newValue||undefined});},placeholder:"Ex. Point at (x, y)",rows:1,resizeType:"vertical"}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:pencilCircle,style:styles$v.button,onClick:()=>{setLoading(true);getPrepopulatedAriaLabel().then(ariaLabel=>{setLoading(false);onChangeProps({ariaLabel});});},children:"Auto-generate"})]})}const styles$v=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"},button:{alignSelf:"start"},caption:{color:color.offBlack64}});
1589
+ const{InfoTip: InfoTip$d}=components;function LockedFigureAria(props){const{ariaLabel,getPrepopulatedAriaLabel,onChangeProps}=props;const id=React.useId();const ariaLabelId=`aria-label-${id}`;const[loading,setLoading]=React.useState(false);return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:styles$u.row,children:[jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:ariaLabelId,children:"Aria label"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(InfoTip$d,{children:["Aria label is used by screen readers to describe content to users who may be visually impaired. ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader."]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(LabelXSmall,{style:styles$u.caption,children:"The figure is hidden from screen readers if this field is left blank."}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextArea,{id:ariaLabelId,value:loading?"Loading...":ariaLabel??"",onChange:newValue=>{onChangeProps({ariaLabel:newValue||undefined});},placeholder:"Ex. Point at (x, y)",rows:1,resizeType:"vertical"}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:pencilCircle,style:styles$u.button,onClick:()=>{setLoading(true);getPrepopulatedAriaLabel().then(ariaLabel=>{setLoading(false);onChangeProps({ariaLabel});});},children:"Auto-generate"})]})}const styles$u=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"},button:{alignSelf:"start"},caption:{color:color.offBlack64}});
1581
1590
 
1582
- const LockedFigureSettingsActions=props=>{const{figureType,onMove,onRemove}=props;return jsxRuntimeExports.jsxs(View,{style:styles$u.container,children:[jsxRuntimeExports.jsx(Button,{startIcon:trashIcon$1,"aria-label":`Delete locked ${figureType}`,onClick:onRemove,kind:"tertiary",style:styles$u.deleteButton,children:"Delete"}),onMove&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the back`,onClick:()=>onMove("back")}),jsxRuntimeExports.jsx(IconButton,{icon:caretUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} backward`,onClick:()=>onMove("backward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} forward`,onClick:()=>onMove("forward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the front`,onClick:()=>onMove("front")})]})]})};const styles$u=StyleSheet.create({container:{width:"100%",flexDirection:"row",alignItems:"center",marginTop:spacing.xxxSmall_4},deleteButton:{marginInlineStart:-spacing.xxxSmall_4}});
1591
+ const LockedFigureSettingsActions=props=>{const{figureType,onMove,onRemove}=props;return jsxRuntimeExports.jsxs(View,{style:styles$t.container,children:[jsxRuntimeExports.jsx(Button,{startIcon:trashIcon$1,"aria-label":`Delete locked ${figureType}`,onClick:onRemove,kind:"tertiary",style:styles$t.deleteButton,children:"Delete"}),onMove&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the back`,onClick:()=>onMove("back")}),jsxRuntimeExports.jsx(IconButton,{icon:caretUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} backward`,onClick:()=>onMove("backward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} forward`,onClick:()=>onMove("forward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the front`,onClick:()=>onMove("front")})]})]})};const styles$t=StyleSheet.create({container:{width:"100%",flexDirection:"row",alignItems:"center",marginTop:spacing.xxxSmall_4},deleteButton:{marginInlineStart:-spacing.xxxSmall_4}});
1583
1592
 
1584
- const{InfoTip: InfoTip$d}=components;function LockedLabelSettings(props){const{type,coord,color: color$1,size,text,expanded,onChangeProps,onMove,onRemove,onToggle,containerStyle}=props;return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:[styles$t.row,styles$t.accordionHeaderContainer],children:[jsxRuntimeExports.jsxs(LabelLarge,{children:["Label (",coord[0],", ",coord[1],")"]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),text!==""&&jsxRuntimeExports.jsx(LabelLarge,{style:[{backgroundColor:color.white,color:lockedFigureColors[color$1]},styles$t.accordionHeader],children:text})]}),containerStyle:containerStyle,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,onChange:newCoords=>{onChangeProps({coord:newCoords});},style:styles$t.spaceUnder}),jsxRuntimeExports.jsxs(View,{style:styles$t.row,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$t.row,styles$t.spaceUnder,{flexGrow:1}],children:["text",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{value:text,placeholder:"ex. $x^2$ or $\\frac{1}{2}$",onChange:newValue=>onChangeProps({text:newValue})})]}),jsxRuntimeExports.jsxs(InfoTip$d,{children:["Surround your text with $ for TeX.",jsxRuntimeExports.jsx("br",{}),"Example: ",`This circle has radius $\\frac{1}{2}$ units.`,jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),'It is important to use TeX when appropriate for accessibility. The above example would be read as "This circle has radius one-half units" by screen readers.']})]}),jsxRuntimeExports.jsxs(View,{style:styles$t.row,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color$1,onChange:newColor=>{onChangeProps({color:newColor});},style:styles$t.spaceUnder}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$t.row,children:["size",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:size,onChange:newValue=>onChangeProps({size:newValue}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"small",label:"small"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"large",label:"large"})]})]})]}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:type,onMove:onMove,onRemove:onRemove})]})}const styles$t=StyleSheet.create({accordionHeaderContainer:{whiteSpace:"nowrap"},accordionHeader:{padding:spacing.xxxSmall_4,marginInlineEnd:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4,textOverflow:"ellipsis",overflow:"hidden"},row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},spaceUnder:{marginBottom:spacing.xSmall_8}});
1593
+ const{InfoTip: InfoTip$c}=components;function LockedLabelSettings(props){const{type,coord,color: color$1,size,text,expanded,onChangeProps,onMove,onRemove,onToggle,containerStyle}=props;return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:[styles$s.row,styles$s.accordionHeaderContainer],children:[jsxRuntimeExports.jsxs(LabelLarge,{children:["Label (",coord[0],", ",coord[1],")"]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),text!==""&&jsxRuntimeExports.jsx(LabelLarge,{style:[{backgroundColor:color.white,color:lockedFigureColors[color$1]},styles$s.accordionHeader],children:text})]}),containerStyle:containerStyle,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,onChange:newCoords=>{onChangeProps({coord:newCoords});},style:styles$s.spaceUnder}),jsxRuntimeExports.jsxs(View,{style:styles$s.row,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$s.row,styles$s.spaceUnder,{flexGrow:1}],children:["text",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{value:text,placeholder:"ex. $x^2$ or $\\frac{1}{2}$",onChange:newValue=>onChangeProps({text:newValue})})]}),jsxRuntimeExports.jsxs(InfoTip$c,{children:["Surround your text with $ for TeX.",jsxRuntimeExports.jsx("br",{}),"Example: ",`This circle has radius $\\frac{1}{2}$ units.`,jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),'It is important to use TeX when appropriate for accessibility. The above example would be read as "This circle has radius one-half units" by screen readers.']})]}),jsxRuntimeExports.jsxs(View,{style:styles$s.row,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color$1,onChange:newColor=>{onChangeProps({color:newColor});},style:styles$s.spaceUnder}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$s.row,children:["size",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:size,onChange:newValue=>onChangeProps({size:newValue}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"small",label:"small"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"large",label:"large"})]})]})]}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:type,onMove:onMove,onRemove:onRemove})]})}const styles$s=StyleSheet.create({accordionHeaderContainer:{whiteSpace:"nowrap"},accordionHeader:{padding:spacing.xxxSmall_4,marginInlineEnd:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4,textOverflow:"ellipsis",overflow:"hidden"},row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},spaceUnder:{marginBottom:spacing.xSmall_8}});
1585
1594
 
1586
1595
  const DEFAULT_COLOR="grayH";function getDefaultFigureForType(type){switch(type){case "point":return {type:"point",coord:[0,0],color:DEFAULT_COLOR,filled:true,labels:[]};case "line":return {type:"line",kind:"line",points:[getDefaultFigureForType("point"),{...getDefaultFigureForType("point"),coord:[2,2]}],color:DEFAULT_COLOR,lineStyle:"solid",showPoint1:false,showPoint2:false,weight:"medium",labels:[]};case "vector":return {type:"vector",points:[[0,0],[2,2]],color:DEFAULT_COLOR,weight:"medium",labels:[]};case "ellipse":return {type:"ellipse",center:[0,0],radius:[1,1],angle:0,color:DEFAULT_COLOR,fillStyle:"none",strokeStyle:"solid",weight:"medium",labels:[]};case "polygon":return {type:"polygon",points:[[0,2],[-1,0],[1,0]],color:DEFAULT_COLOR,showVertices:false,fillStyle:"none",strokeStyle:"solid",weight:"medium",labels:[]};case "function":return {type:"function",color:DEFAULT_COLOR,strokeStyle:"solid",weight:"medium",equation:"x^2",domain:[-Infinity,Infinity],directionalAxis:"x",labels:[]};case "label":return {type:"label",coord:[0,0],text:"label",color:DEFAULT_COLOR,size:"medium"};default:throw new UnreachableCaseError(type)}}function generateLockedFigureAppearanceDescription(color,strokeStyle="solid",fill,weight="medium"){const convertedColor=color==="grayH"?"gray":color;const weightString=weight==="medium"?"":` ${weight}`;const baseAppearance=`. Appearance${weightString} ${strokeStyle} ${convertedColor}`;switch(fill){case "none":return `${baseAppearance} border, with no fill.`;case "white":return `${baseAppearance} border, with a white fill.`;case "solid":case "translucent":return `${baseAppearance} border, with a ${fill} ${convertedColor} fill.`;case undefined:return `${baseAppearance}.`;default:throw new UnreachableCaseError(fill)}}async function generateSpokenMathDetails(mathString){const engine=await SpeechRuleEngine.setup("en");let convertedSpeech="";const parsedContent=mathOnlyParser(mathString);for(const piece of parsedContent){switch(piece.type){case "math":convertedSpeech+=engine.texToSpeech(piece.content);break;case "specialCharacter":convertedSpeech+=piece.content.length>1?piece.content.slice(1):piece.content;break;default:convertedSpeech+=piece.content;break}}return convertedSpeech}async function joinLabelsAsSpokenMath(labels){if(labels.length===0){return ""}const spokenLabelPromises=labels.map(label=>{return generateSpokenMathDetails(label.text)});const spokenLabels=await Promise.all(spokenLabelPromises);return ` ${spokenLabels.join(", ")}`}
1587
1596
 
1588
- const{convertRadiansToDegrees}=angles;const{InfoTip: InfoTip$c}=components;const LockedEllipseSettings=props=>{const{center,radius,angle,color,labels,ariaLabel,fillStyle,strokeStyle,weight,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenCenterX=await generateSpokenMathDetails(`$${center[0]}$`);const spokenCenterY=await generateSpokenMathDetails(`$${center[1]}$`);const spokenRotation=await generateSpokenMathDetails(`$${convertRadiansToDegrees(angle)}$`);const isCircle=radius[0]===radius[1];let str="";if(isCircle){str+=`Circle${visiblelabel} with radius ${radius[0]}`;}else {str+=`Ellipse${visiblelabel} with x radius ${radius[0]} and y radius ${radius[1]}`;}str+=`, centered at ${spokenCenterX} comma ${spokenCenterY}`;if(!isCircle&&angle!==0){str+=`, rotated by ${spokenRotation} degrees`;}const ellipseAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=ellipseAppearance;return str}function handleCenterChange(newCoord){const xOffset=newCoord[0]-center[0];const yOffset=newCoord[1]-center[1];const newProps={center:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$s.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(EllipseSwatch,{color:props.color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:styles$s.row,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:center,style:styles$s.spaceUnder,onChange:handleCenterChange}),jsxRuntimeExports.jsx(View,{style:styles$s.spaceUnder,children:jsxRuntimeExports.jsx(InfoTip$c,{children:"The coordinates for the center of the ellipse."})})]}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:radius,labels:["x radius","y radius"],style:styles$s.spaceUnder,onChange:newCoords=>onChangeProps({radius:newCoords})}),jsxRuntimeExports.jsx(AngleInput,{angle:angle,onChange:newAngle=>onChangeProps({angle:newAngle})}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:[styles$s.row,styles$s.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$s.row,styles$s.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$s.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$s.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$s.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[center[0],center[1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$s.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$s=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1597
+ const{convertRadiansToDegrees}=angles;const{InfoTip: InfoTip$b}=components;const LockedEllipseSettings=props=>{const{center,radius,angle,color,labels,ariaLabel,fillStyle,strokeStyle,weight,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenCenterX=await generateSpokenMathDetails(`$${center[0]}$`);const spokenCenterY=await generateSpokenMathDetails(`$${center[1]}$`);const spokenRotation=await generateSpokenMathDetails(`$${convertRadiansToDegrees(angle)}$`);const isCircle=radius[0]===radius[1];let str="";if(isCircle){str+=`Circle${visiblelabel} with radius ${radius[0]}`;}else {str+=`Ellipse${visiblelabel} with x radius ${radius[0]} and y radius ${radius[1]}`;}str+=`, centered at ${spokenCenterX} comma ${spokenCenterY}`;if(!isCircle&&angle!==0){str+=`, rotated by ${spokenRotation} degrees`;}const ellipseAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=ellipseAppearance;return str}function handleCenterChange(newCoord){const xOffset=newCoord[0]-center[0];const yOffset=newCoord[1]-center[1];const newProps={center:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(EllipseSwatch,{color:props.color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:center,style:styles$r.spaceUnder,onChange:handleCenterChange}),jsxRuntimeExports.jsx(View,{style:styles$r.spaceUnder,children:jsxRuntimeExports.jsx(InfoTip$b,{children:"The coordinates for the center of the ellipse."})})]}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:radius,labels:["x radius","y radius"],style:styles$r.spaceUnder,onChange:newCoords=>onChangeProps({radius:newCoords})}),jsxRuntimeExports.jsx(AngleInput,{angle:angle,onChange:newAngle=>onChangeProps({angle:newAngle})}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:[styles$r.row,styles$r.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$r.row,styles$r.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$r.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$r.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$r.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[center[0],center[1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$r.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$r=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1589
1598
 
1590
- const LineSwatch=props=>{const{color,lineStyle}=props;return jsxRuntimeExports.jsx(View,{style:styles$r.container,children:jsxRuntimeExports.jsx(View,{"aria-label":`${color}, ${lineStyle}`,style:[styles$r.lineSwatch,{border:`5px ${lineStyle} ${lockedFigureColors[color]}`}]})})};const styles$r=StyleSheet.create({container:{backgroundColor:color.white,justifyContent:"center",padding:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4},lineSwatch:{width:40}});
1599
+ const LineSwatch=props=>{const{color,lineStyle}=props;return jsxRuntimeExports.jsx(View,{style:styles$q.container,children:jsxRuntimeExports.jsx(View,{"aria-label":`${color}, ${lineStyle}`,style:[styles$q.lineSwatch,{border:`5px ${lineStyle} ${lockedFigureColors[color]}`}]})})};const styles$q=StyleSheet.create({container:{backgroundColor:color.white,justifyContent:"center",padding:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4},lineSwatch:{width:40}});
1591
1600
 
1592
1601
  const examples={linear:["x + 5","1/2x - 2"],polynomial:["1/2x^2 + 3x - 4","(1/3)x^3 - 2x^2 + 3x - 4"],trigonometric:["sin(x) * 3","arctan(2x) + 4"]};
1593
1602
 
1594
- const LockedFunctionSettings=props=>{const{color:lineColor,strokeStyle,equation,directionalAxis,domain,weight,ariaLabel,onChangeProps,onMove,onRemove}=props;const labels=props.labels;const equationPrefix=directionalAxis==="x"?"y=":"x=";const lineLabel=`Function (${equationPrefix}${equation})`;const getDomainStringValues=domain=>{return [Number.isFinite(domain[0])?domain[0].toString():"",Number.isFinite(domain[1])?domain[1].toString():""]};const[domainEntries,setDomainEntries]=useState(getDomainStringValues(domain));const[exampleCategory,setExampleCategory]=useState("");useEffect(()=>{setDomainEntries(getDomainStringValues(domain));},[domain]);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);let str=`Function${visiblelabel} with equation ${equationPrefix}${equation}`;if(Number.isFinite(domain[0])||Number.isFinite(domain[1])){str+=`, domain from ${domain[0]} to ${domain[1]}`;}const functionAppearance=generateLockedFigureAppearanceDescription(lineColor,strokeStyle,undefined,weight);str+=functionAppearance;return str}function handlePropChange(property,newValue){const updatedProps={};updatedProps[property]=newValue;onChangeProps(updatedProps);}function handleDomainChange(limitIndex,newValueString){const newDomainEntries=[...domainEntries];newDomainEntries[limitIndex]=newValueString;setDomainEntries(newDomainEntries);const newDomain=[...domain];let newValue=parseFloat(newValueString);if(newValueString===""&&limitIndex===0){newValue=-Infinity;}else if(newValueString===""&&limitIndex===1){newValue=Infinity;}newDomain[limitIndex]=newValue;onChangeProps({domain:newDomain});}const exampleCategories=Object.keys(examples);const exampleCategorySelected=exampleCategory!=="";const exampleContent=exampleCategorySelected?examples[exampleCategory]:["Select category to see example equations"];function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$q.row,children:[jsxRuntimeExports.jsx(LabelLarge,{style:styles$q.accordionHeader,children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:[styles$q.row,{marginBottom:sizing.size_080}],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:newValue=>{handlePropChange("strokeStyle",newValue);}})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsxs(View,{style:[styles$q.row,styles$q.rowSpace],children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:directionalAxis,onChange:newValue=>{handlePropChange("directionalAxis",newValue);},"aria-label":"equation prefix",style:[styles$q.dropdownLabel,styles$q.axisMenu],placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"x",label:"y ="}),jsxRuntimeExports.jsx(OptionItem,{value:"y",label:"x ="})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{type:"text","aria-label":"equation",value:equation,onChange:newValue=>{handlePropChange("equation",newValue);},style:[styles$q.textField]})]}),jsxRuntimeExports.jsxs(View,{style:[styles$q.row,styles$q.rowSpace],children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$q.dropdownLabel,styles$q.domainMin],children:["domain min",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextField,{type:"number",style:styles$q.domainMinField,value:domainEntries[0],onChange:newValue=>{handleDomainChange(0,newValue);}})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label","aria-label":"domain max",style:[styles$q.dropdownLabel,styles$q.domainMax],children:["max",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextField,{type:"number",style:styles$q.domainMaxField,value:domainEntries[1],onChange:newValue=>{handleDomainChange(1,newValue);}})]})]}),jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:"Example Functions"}),expanded:false,containerStyle:styles$q.exampleWorkspace,panelStyle:styles$q.exampleAccordionPanel,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$q.dropdownLabel,children:["Choose a category",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:exampleCategory,onChange:setExampleCategory,placeholder:"examples",children:exampleCategories.map(category=>{return jsxRuntimeExports.jsx(OptionItem,{value:category,label:category},category)})})]}),exampleCategorySelected&&jsxRuntimeExports.jsx("ul",{className:css(styles$q.exampleContainer),children:exampleContent.map((example,index)=>jsxRuntimeExports.jsx(ExampleItem,{category:exampleCategory,example:example,index:index,pasteEquationFn:handlePropChange},index))})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>jsxRuntimeExports.jsx(LockedLabelSettings,{...label,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$q.labelContainer},labelIndex)),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[0,-labels.length],color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$q.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const ExampleItem=props=>{const{category,example,index,pasteEquationFn}=props;const exampleId=useId();return jsxRuntimeExports.jsxs("li",{className:css(styles$q.exampleRow),children:[jsxRuntimeExports.jsx(IconButton,{icon:autoPasteIcon,kind:"tertiary","aria-label":"paste example","aria-describedby":exampleId,onClick:()=>pasteEquationFn("equation",example),size:"medium",style:styles$q.copyPasteButton}),jsxRuntimeExports.jsx(IconButton,{icon:copyIcon,kind:"tertiary","aria-label":"copy example","aria-describedby":exampleId,onClick:()=>navigator.clipboard.writeText(example),size:"medium",style:styles$q.copyPasteButton}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$q.exampleContent,id:exampleId,children:example})]},`${category}-${index}`)};const styles$q=StyleSheet.create({accordionHeader:{textOverflow:"ellipsis",maxWidth:"calc(100% - 64px)",overflow:"hidden",whiteSpace:"nowrap"},axisMenu:{minWidth:"auto"},copyPasteButton:{flexShrink:"0",margin:"0 2px"},domainMin:{justifyContent:"space-between",width:"calc(((100% - 141px) / 2) + 88.7px)",textWrap:"nowrap"},domainMinField:{width:"calc(100% - 88.7px)"},domainMax:{width:"calc(((100% - 141px) / 2) + 36.2px)"},domainMaxField:{width:"calc(100% - 36.2px)"},dropdownLabel:{alignItems:"center",display:"flex"},exampleAccordionPanel:{alignItems:"start",paddingBottom:"12px",flexDirection:"row",flexWrap:"wrap"},exampleContainer:{background:"white",border:`1px solid ${color.fadedOffBlack16}`,borderRadius:"4px",flexGrow:"1",listStyleType:"none",maxHeight:"88px",margin:"8px 0 0 0",overflowY:"scroll",padding:"4px 12px 4px 4px"},exampleContent:{fontFamily:`"Lato", sans-serif`,flexGrow:"1",color:color.offBlack},exampleRow:{alignItems:"center",display:"flex",flexDirection:"row",minHeight:"44px"},exampleWorkspace:{background:color.white50},rowSpace:{marginTop:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{flexGrow:"1"},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1603
+ const LockedFunctionSettings=props=>{const{color:lineColor,strokeStyle,equation,directionalAxis,domain,weight,ariaLabel,onChangeProps,onMove,onRemove}=props;const labels=props.labels;const equationPrefix=directionalAxis==="x"?"y=":"x=";const lineLabel=`Function (${equationPrefix}${equation})`;const getDomainStringValues=domain=>{return [Number.isFinite(domain[0])?domain[0].toString():"",Number.isFinite(domain[1])?domain[1].toString():""]};const[domainEntries,setDomainEntries]=useState(getDomainStringValues(domain));const[exampleCategory,setExampleCategory]=useState("");useEffect(()=>{setDomainEntries(getDomainStringValues(domain));},[domain]);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);let str=`Function${visiblelabel} with equation ${equationPrefix}${equation}`;if(Number.isFinite(domain[0])||Number.isFinite(domain[1])){str+=`, domain from ${domain[0]} to ${domain[1]}`;}const functionAppearance=generateLockedFigureAppearanceDescription(lineColor,strokeStyle,undefined,weight);str+=functionAppearance;return str}function handlePropChange(property,newValue){const updatedProps={};updatedProps[property]=newValue;onChangeProps(updatedProps);}function handleDomainChange(limitIndex,newValueString){const newDomainEntries=[...domainEntries];newDomainEntries[limitIndex]=newValueString;setDomainEntries(newDomainEntries);const newDomain=[...domain];let newValue=parseFloat(newValueString);if(newValueString===""&&limitIndex===0){newValue=-Infinity;}else if(newValueString===""&&limitIndex===1){newValue=Infinity;}newDomain[limitIndex]=newValue;onChangeProps({domain:newDomain});}const exampleCategories=Object.keys(examples);const exampleCategorySelected=exampleCategory!=="";const exampleContent=exampleCategorySelected?examples[exampleCategory]:["Select category to see example equations"];function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$p.row,children:[jsxRuntimeExports.jsx(LabelLarge,{style:styles$p.accordionHeader,children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:[styles$p.row,{marginBottom:sizing.size_080}],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:newValue=>{handlePropChange("strokeStyle",newValue);}})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsxs(View,{style:[styles$p.row,styles$p.rowSpace],children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:directionalAxis,onChange:newValue=>{handlePropChange("directionalAxis",newValue);},"aria-label":"equation prefix",style:[styles$p.dropdownLabel,styles$p.axisMenu],placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"x",label:"y ="}),jsxRuntimeExports.jsx(OptionItem,{value:"y",label:"x ="})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{type:"text","aria-label":"equation",value:equation,onChange:newValue=>{handlePropChange("equation",newValue);},style:[styles$p.textField]})]}),jsxRuntimeExports.jsxs(View,{style:[styles$p.row,styles$p.rowSpace],children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$p.dropdownLabel,styles$p.domainMin],children:["domain min",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextField,{type:"number",style:styles$p.domainMinField,value:domainEntries[0],onChange:newValue=>{handleDomainChange(0,newValue);}})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label","aria-label":"domain max",style:[styles$p.dropdownLabel,styles$p.domainMax],children:["max",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextField,{type:"number",style:styles$p.domainMaxField,value:domainEntries[1],onChange:newValue=>{handleDomainChange(1,newValue);}})]})]}),jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:"Example Functions"}),expanded:false,containerStyle:styles$p.exampleWorkspace,panelStyle:styles$p.exampleAccordionPanel,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$p.dropdownLabel,children:["Choose a category",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:exampleCategory,onChange:setExampleCategory,placeholder:"examples",children:exampleCategories.map(category=>{return jsxRuntimeExports.jsx(OptionItem,{value:category,label:category},category)})})]}),exampleCategorySelected&&jsxRuntimeExports.jsx("ul",{className:css(styles$p.exampleContainer),children:exampleContent.map((example,index)=>jsxRuntimeExports.jsx(ExampleItem,{category:exampleCategory,example:example,index:index,pasteEquationFn:handlePropChange},index))})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$p.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$p.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>jsxRuntimeExports.jsx(LockedLabelSettings,{...label,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$p.labelContainer},labelIndex)),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[0,-labels.length],color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$p.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const ExampleItem=props=>{const{category,example,index,pasteEquationFn}=props;const exampleId=useId();return jsxRuntimeExports.jsxs("li",{className:css(styles$p.exampleRow),children:[jsxRuntimeExports.jsx(IconButton,{icon:autoPasteIcon,kind:"tertiary","aria-label":"paste example","aria-describedby":exampleId,onClick:()=>pasteEquationFn("equation",example),size:"medium",style:styles$p.copyPasteButton}),jsxRuntimeExports.jsx(IconButton,{icon:copyIcon,kind:"tertiary","aria-label":"copy example","aria-describedby":exampleId,onClick:()=>navigator.clipboard.writeText(example),size:"medium",style:styles$p.copyPasteButton}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$p.exampleContent,id:exampleId,children:example})]},`${category}-${index}`)};const styles$p=StyleSheet.create({accordionHeader:{textOverflow:"ellipsis",maxWidth:"calc(100% - 64px)",overflow:"hidden",whiteSpace:"nowrap"},axisMenu:{minWidth:"auto"},copyPasteButton:{flexShrink:"0",margin:"0 2px"},domainMin:{justifyContent:"space-between",width:"calc(((100% - 141px) / 2) + 88.7px)",textWrap:"nowrap"},domainMinField:{width:"calc(100% - 88.7px)"},domainMax:{width:"calc(((100% - 141px) / 2) + 36.2px)"},domainMaxField:{width:"calc(100% - 36.2px)"},dropdownLabel:{alignItems:"center",display:"flex"},exampleAccordionPanel:{alignItems:"start",paddingBottom:"12px",flexDirection:"row",flexWrap:"wrap"},exampleContainer:{background:"white",border:`1px solid ${color.fadedOffBlack16}`,borderRadius:"4px",flexGrow:"1",listStyleType:"none",maxHeight:"88px",margin:"8px 0 0 0",overflowY:"scroll",padding:"4px 12px 4px 4px"},exampleContent:{fontFamily:`"Lato", sans-serif`,flexGrow:"1",color:color.offBlack},exampleRow:{alignItems:"center",display:"flex",flexDirection:"row",minHeight:"44px"},exampleWorkspace:{background:color.white50},rowSpace:{marginTop:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{flexGrow:"1"},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1595
1604
 
1596
- const LabeledSwitch=props=>{const{checked,label,style,onChange}=props;const switchId=useId();return jsxRuntimeExports.jsxs(View,{style:[styles$p.row,style],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:checked,onChange:onChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:switchId,children:label})]})};const styles$p=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"}});
1605
+ const LabeledSwitch=props=>{const{checked,label,style,onChange}=props;const switchId=useId();return jsxRuntimeExports.jsxs(View,{style:[styles$o.row,style],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:checked,onChange:onChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:switchId,children:label})]})};const styles$o=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"}});
1597
1606
 
1598
- const LockedPointSettings=props=>{const{headerLabel,coord,color:pointColor,filled=true,labels,ariaLabel,onChangeProps,onMove,onRemove,showPoint,error,expanded,onTogglePoint,onToggle}=props;const isDefiningPoint=!onMove&&!onRemove;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenX=await generateSpokenMathDetails(`$${coord[0]}$`);const spokenY=await generateSpokenMathDetails(`$${coord[1]}$`);let str=`Point${visiblelabel} at ${spokenX} comma ${spokenY}`;const pointAppearance=generateLockedFigureAppearanceDescription(pointColor);str+=pointAppearance;return str}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleCoordChange(newCoord){const xOffset=newCoord[0]-coord[0];const yOffset=newCoord[1]-coord[1];const newProps={coord:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,containerStyle:isDefiningPoint?styles$o.definingContainer:undefined,panelStyle:isDefiningPoint?styles$o.definingPanel:undefined,header:jsxRuntimeExports.jsxs(View,{style:styles$o.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`${headerLabel||"Point"} (${coord[0]}, ${coord[1]})`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(ColorSwatch,{color:pointColor,filled:filled})]}),children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,style:styles$o.spaceUnder,onChange:handleCoordChange,error:!!error}),onTogglePoint&&jsxRuntimeExports.jsx(LabeledSwitch,{label:"show point on graph",checked:!!showPoint,style:showPoint&&styles$o.spaceUnder,onChange:onTogglePoint}),(!isDefiningPoint||showPoint)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:pointColor,onChange:handleColorChange,style:styles$o.spaceUnder}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"open point",checked:!filled,onChange:newValue=>{onChangeProps({filled:!newValue});}})]}),!isDefiningPoint&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$o.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$o.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,containerStyle:!isDefiningPoint&&styles$o.lockedPointLabelContainer,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);}})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[coord[0]+.5,coord[1]-labels.length],color:pointColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$o.addButton,children:"Add visible label"}),onRemove&&jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$o=StyleSheet.create({definingContainer:{marginTop:spacing.xSmall_8,marginBottom:0,marginLeft:-spacing.xxxSmall_4,marginRight:-spacing.xxxSmall_4,backgroundColor:color.white},definingPanel:{paddingBottom:spacing.xxSmall_6},lockedPointLabelContainer:{backgroundColor:color.white},row:{flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1607
+ const LockedPointSettings=props=>{const{headerLabel,coord,color:pointColor,filled=true,labels,ariaLabel,onChangeProps,onMove,onRemove,showPoint,error,expanded,onTogglePoint,onToggle}=props;const isDefiningPoint=!onMove&&!onRemove;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenX=await generateSpokenMathDetails(`$${coord[0]}$`);const spokenY=await generateSpokenMathDetails(`$${coord[1]}$`);let str=`Point${visiblelabel} at ${spokenX} comma ${spokenY}`;const pointAppearance=generateLockedFigureAppearanceDescription(pointColor);str+=pointAppearance;return str}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleCoordChange(newCoord){const xOffset=newCoord[0]-coord[0];const yOffset=newCoord[1]-coord[1];const newProps={coord:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,containerStyle:isDefiningPoint?styles$n.definingContainer:undefined,panelStyle:isDefiningPoint?styles$n.definingPanel:undefined,header:jsxRuntimeExports.jsxs(View,{style:styles$n.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`${headerLabel||"Point"} (${coord[0]}, ${coord[1]})`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(ColorSwatch,{color:pointColor,filled:filled})]}),children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,style:styles$n.spaceUnder,onChange:handleCoordChange,error:!!error}),onTogglePoint&&jsxRuntimeExports.jsx(LabeledSwitch,{label:"show point on graph",checked:!!showPoint,style:showPoint&&styles$n.spaceUnder,onChange:onTogglePoint}),(!isDefiningPoint||showPoint)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:pointColor,onChange:handleColorChange,style:styles$n.spaceUnder}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"open point",checked:!filled,onChange:newValue=>{onChangeProps({filled:!newValue});}})]}),!isDefiningPoint&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$n.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$n.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,containerStyle:!isDefiningPoint&&styles$n.lockedPointLabelContainer,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);}})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[coord[0]+.5,coord[1]-labels.length],color:pointColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$n.addButton,children:"Add visible label"}),onRemove&&jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$n=StyleSheet.create({definingContainer:{marginTop:spacing.xSmall_8,marginBottom:0,marginLeft:-spacing.xxxSmall_4,marginRight:-spacing.xxxSmall_4,backgroundColor:color.white},definingPanel:{paddingBottom:spacing.xxSmall_6},lockedPointLabelContainer:{backgroundColor:color.white},row:{flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1599
1608
 
1600
1609
  const lengthZeroStr="The line cannot have length 0.";const LockedLineSettings=props=>{const{kind,points,color:lineColor,lineStyle="solid",showPoint1,showPoint2,weight,labels,ariaLabel,onChangeProps,onMove,onRemove}=props;const[point1,point2]=points;const capitalizeKind=kind.charAt(0).toUpperCase()+kind.slice(1);const lineLabel=`${capitalizeKind} (${point1.coord[0]},
1601
- ${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;const isInvalid=vector.equal(point1.coord,point2.coord);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const point1VisibleLabel=await joinLabelsAsSpokenMath(point1.labels);const point2VisibleLabel=await joinLabelsAsSpokenMath(point2.labels);const spokenPoint1X=await generateSpokenMathDetails(`$${point1.coord[0]}$`);const spokenPoint1Y=await generateSpokenMathDetails(`$${point1.coord[1]}$`);const spokenPoint2X=await generateSpokenMathDetails(`$${point2.coord[0]}$`);const spokenPoint2Y=await generateSpokenMathDetails(`$${point2.coord[1]}$`);let str;switch(kind){case "line":str=`${capitalizeKind}${visiblelabel} through point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} and point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "ray":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} through point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "segment":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} to point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;default:throw new UnreachableCaseError(kind,"Unknown line kind")}const lineAppearance=generateLockedFigureAppearanceDescription(lineColor,lineStyle,undefined,weight);str+=lineAppearance;return str}function handleChangePoint(newPointProps,index){const newPoints=[...points];newPoints[index]={...points[index],...newPointProps};const oldMidpoint=vec.midpoint(points[0].coord,points[1].coord);const newMidpoint=vec.midpoint(newPoints[0].coord,newPoints[1].coord);const offset=[newMidpoint[0]-oldMidpoint[0],newMidpoint[1]-oldMidpoint[1]];const newLabels=labels.map((label,labelIndex)=>({...label,coord:[label.coord[0]+offset[0],label.coord[1]+offset[1]]}));onChangeProps({points:newPoints,labels:newLabels});}function handleColorChange(newColor){const newLabels=labels.map(label=>({...label,color:newColor}));onChangeProps({color:newColor,points:[{...point1,color:newColor,labels:point1.labels.map(label=>({...label,color:newColor}))},{...point2,color:newColor,labels:point2.labels.map(label=>({...label,color:newColor}))}],labels:newLabels});}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$n.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:lineStyle})]}),children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$n.row,styles$n.spaceUnder],children:["kind",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:kind,onChange:value=>onChangeProps({kind:value}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"line",label:"line"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"ray"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"segment"})]})]}),jsxRuntimeExports.jsxs(View,{style:[styles$n.row,styles$n.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:lineStyle,onChange:value=>onChangeProps({lineStyle:value})})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(LabelMedium,{style:styles$n.errorText,children:lengthZeroStr}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 1",expanded:true,showPoint:showPoint1,error:isInvalid?lengthZeroStr:null,...point1,onTogglePoint:newValue=>onChangeProps({showPoint1:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,0)}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 2",expanded:true,showPoint:showPoint2,error:isInvalid?lengthZeroStr:null,...point2,onTogglePoint:newValue=>onChangeProps({showPoint2:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,1)}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$n.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$n.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$n.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),vec.midpoint(points[0].coord,points[1].coord));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$n.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$n=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},errorText:{color:color.red},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1610
+ ${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;const isInvalid=vector.equal(point1.coord,point2.coord);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const point1VisibleLabel=await joinLabelsAsSpokenMath(point1.labels);const point2VisibleLabel=await joinLabelsAsSpokenMath(point2.labels);const spokenPoint1X=await generateSpokenMathDetails(`$${point1.coord[0]}$`);const spokenPoint1Y=await generateSpokenMathDetails(`$${point1.coord[1]}$`);const spokenPoint2X=await generateSpokenMathDetails(`$${point2.coord[0]}$`);const spokenPoint2Y=await generateSpokenMathDetails(`$${point2.coord[1]}$`);let str;switch(kind){case "line":str=`${capitalizeKind}${visiblelabel} through point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} and point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "ray":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} through point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "segment":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} to point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;default:throw new UnreachableCaseError(kind,"Unknown line kind")}const lineAppearance=generateLockedFigureAppearanceDescription(lineColor,lineStyle,undefined,weight);str+=lineAppearance;return str}function handleChangePoint(newPointProps,index){const newPoints=[...points];newPoints[index]={...points[index],...newPointProps};const oldMidpoint=vec.midpoint(points[0].coord,points[1].coord);const newMidpoint=vec.midpoint(newPoints[0].coord,newPoints[1].coord);const offset=[newMidpoint[0]-oldMidpoint[0],newMidpoint[1]-oldMidpoint[1]];const newLabels=labels.map((label,labelIndex)=>({...label,coord:[label.coord[0]+offset[0],label.coord[1]+offset[1]]}));onChangeProps({points:newPoints,labels:newLabels});}function handleColorChange(newColor){const newLabels=labels.map(label=>({...label,color:newColor}));onChangeProps({color:newColor,points:[{...point1,color:newColor,labels:point1.labels.map(label=>({...label,color:newColor}))},{...point2,color:newColor,labels:point2.labels.map(label=>({...label,color:newColor}))}],labels:newLabels});}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$m.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:lineStyle})]}),children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$m.row,styles$m.spaceUnder],children:["kind",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:kind,onChange:value=>onChangeProps({kind:value}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"line",label:"line"}),jsxRuntimeExports.jsx(OptionItem,{value:"ray",label:"ray"}),jsxRuntimeExports.jsx(OptionItem,{value:"segment",label:"segment"})]})]}),jsxRuntimeExports.jsxs(View,{style:[styles$m.row,styles$m.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:lineStyle,onChange:value=>onChangeProps({lineStyle:value})})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(LabelMedium,{style:styles$m.errorText,children:lengthZeroStr}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 1",expanded:true,showPoint:showPoint1,error:isInvalid?lengthZeroStr:null,...point1,onTogglePoint:newValue=>onChangeProps({showPoint1:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,0)}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 2",expanded:true,showPoint:showPoint2,error:isInvalid?lengthZeroStr:null,...point2,onTogglePoint:newValue=>onChangeProps({showPoint2:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,1)}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$m.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$m.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$m.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),vec.midpoint(points[0].coord,points[1].coord));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$m.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$m=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},errorText:{color:color.red},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1602
1611
 
1603
- const PolygonSwatch=props=>{const{color,fillStyle,strokeStyle}=props;return jsxRuntimeExports.jsx(View,{"aria-label":`${color}, stroke ${strokeStyle}, fill ${fillStyle}`,style:[styles$m.container,{border:`4px ${strokeStyle} ${lockedFigureColors[color]}`}],children:jsxRuntimeExports.jsx(View,{style:[styles$m.innerSquare,{backgroundColor:lockedFigureColors[color],opacity:fillStyle==="white"?0:lockedFigureFillStyles[fillStyle]}]})})};const styles$m=StyleSheet.create({container:{outline:`2px solid ${color.offWhite}`,width:spacing.large_24,height:spacing.large_24,backgroundColor:color.white,alignItems:"center",justifyContent:"center"},innerSquare:{width:20,height:20}});
1612
+ const PolygonSwatch=props=>{const{color,fillStyle,strokeStyle}=props;return jsxRuntimeExports.jsx(View,{"aria-label":`${color}, stroke ${strokeStyle}, fill ${fillStyle}`,style:[styles$l.container,{border:`4px ${strokeStyle} ${lockedFigureColors[color]}`}],children:jsxRuntimeExports.jsx(View,{style:[styles$l.innerSquare,{backgroundColor:lockedFigureColors[color],opacity:fillStyle==="white"?0:lockedFigureFillStyles[fillStyle]}]})})};const styles$l=StyleSheet.create({container:{outline:`2px solid ${color.offWhite}`,width:spacing.large_24,height:spacing.large_24,backgroundColor:color.white,alignItems:"center",justifyContent:"center"},innerSquare:{width:20,height:20}});
1604
1613
 
1605
- const LockedPolygonSettings=props=>{const{points,color,showVertices,fillStyle,strokeStyle,weight,labels,ariaLabel,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);let str=`Polygon${visiblelabel} with ${points.length} sides, vertices at `;const pointsList=await Promise.all(points.map(async([x,y])=>{const spokenX=await generateSpokenMathDetails(`$${x}$`);const spokenY=await generateSpokenMathDetails(`$${y}$`);return `${spokenX} comma ${spokenY}`}));str+=pointsList.join(", ");const polygonAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=polygonAppearance;return str}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handlePolygonMove(movement){switch(movement){case "up":onChangeProps({points:points.map(([x,y])=>[x,y+1]),labels:labels.map(label=>({...label,coord:[label.coord[0],label.coord[1]+1]}))});break;case "down":onChangeProps({points:points.map(([x,y])=>[x,y-1]),labels:labels.map(label=>({...label,coord:[label.coord[0],label.coord[1]-1]}))});break;case "left":onChangeProps({points:points.map(([x,y])=>[x-1,y]),labels:labels.map(label=>({...label,coord:[label.coord[0]-1,label.coord[1]]}))});break;case "right":onChangeProps({points:points.map(([x,y])=>[x+1,y]),labels:labels.map(label=>({...label,coord:[label.coord[0]+1,label.coord[1]]}))});break}}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$l.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Polygon, ${points.length} sides`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(PolygonSwatch,{color:color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:[styles$l.row,styles$l.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$l.row,styles$l.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:styles$l.spaceUnder}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value}),containerStyle:styles$l.spaceUnder}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"show vertices",checked:showVertices,onChange:newValue=>onChangeProps({showVertices:newValue}),style:styles$l.spaceUnder}),jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:"Points"}),expanded:true,containerStyle:styles$l.pointAccordionContainer,panelStyle:styles$l.pointAccordionPanel,children:[points.map((point,index)=>{const pointLabel=String.fromCharCode(65+index);return jsxRuntimeExports.jsxs(View,{style:[styles$l.row,styles$l.spaceUnder],children:[jsxRuntimeExports.jsx(LabelLarge,{children:`${pointLabel}:`}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:point,labels:["x","y"],onChange:newValue=>{const newPoints=[...points];newPoints[index]=newValue;props.onChangeProps({points:newPoints});}}),points.length>3&&jsxRuntimeExports.jsx(IconButton,{"aria-label":`Delete polygon point ${pointLabel}`,icon:minusCircle,kind:"tertiary",actionType:"destructive",onClick:()=>{const newPoints=[...points];newPoints.splice(index,1);props.onChangeProps({points:newPoints});},style:styles$l.icon})]},`locked-polygon-point-index-${index}`)}),jsxRuntimeExports.jsxs(View,{style:[styles$l.row,styles$l.polygonActionsContainer],children:[jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{props.onChangeProps({points:[...points,[0,0]]});},children:"Add point"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(View,{style:styles$l.movementButtonsContainer,children:[jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon up",size:"small",icon:arrowFatUp,kind:"tertiary",onClick:()=>handlePolygonMove("up")}),jsxRuntimeExports.jsxs(View,{style:styles$l.row,children:[jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon left",size:"small",icon:arrowFatLeft,kind:"tertiary",onClick:()=>handlePolygonMove("left")}),jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon down",size:"small",icon:arrowFatDown,kind:"tertiary",onClick:()=>handlePolygonMove("down")}),jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon right",size:"small",icon:arrowFatRight,kind:"tertiary",onClick:()=>handlePolygonMove("right")})]})]})]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$l.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$l.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$l.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[points[0][0],points[0][1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$l.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$l=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},pointAccordionContainer:{backgroundColor:color.white},pointAccordionPanel:{alignItems:"start"},icon:{marginInlineStart:spacing.xxxSmall_4},polygonActionsContainer:{width:"100%"},movementButtonsContainer:{display:"flex",flexDirection:"column",alignItems:"center",minWidth:"fit-content"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1614
+ const LockedPolygonSettings=props=>{const{points,color,showVertices,fillStyle,strokeStyle,weight,labels,ariaLabel,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);let str=`Polygon${visiblelabel} with ${points.length} sides, vertices at `;const pointsList=await Promise.all(points.map(async([x,y])=>{const spokenX=await generateSpokenMathDetails(`$${x}$`);const spokenY=await generateSpokenMathDetails(`$${y}$`);return `${spokenX} comma ${spokenY}`}));str+=pointsList.join(", ");const polygonAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=polygonAppearance;return str}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handlePolygonMove(movement){switch(movement){case "up":onChangeProps({points:points.map(([x,y])=>[x,y+1]),labels:labels.map(label=>({...label,coord:[label.coord[0],label.coord[1]+1]}))});break;case "down":onChangeProps({points:points.map(([x,y])=>[x,y-1]),labels:labels.map(label=>({...label,coord:[label.coord[0],label.coord[1]-1]}))});break;case "left":onChangeProps({points:points.map(([x,y])=>[x-1,y]),labels:labels.map(label=>({...label,coord:[label.coord[0]-1,label.coord[1]]}))});break;case "right":onChangeProps({points:points.map(([x,y])=>[x+1,y]),labels:labels.map(label=>({...label,coord:[label.coord[0]+1,label.coord[1]]}))});break}}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$k.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Polygon, ${points.length} sides`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(PolygonSwatch,{color:color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:[styles$k.row,styles$k.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$k.row,styles$k.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:styles$k.spaceUnder}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value}),containerStyle:styles$k.spaceUnder}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"show vertices",checked:showVertices,onChange:newValue=>onChangeProps({showVertices:newValue}),style:styles$k.spaceUnder}),jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:"Points"}),expanded:true,containerStyle:styles$k.pointAccordionContainer,panelStyle:styles$k.pointAccordionPanel,children:[points.map((point,index)=>{const pointLabel=String.fromCharCode(65+index);return jsxRuntimeExports.jsxs(View,{style:[styles$k.row,styles$k.spaceUnder],children:[jsxRuntimeExports.jsx(LabelLarge,{children:`${pointLabel}:`}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:point,labels:["x","y"],onChange:newValue=>{const newPoints=[...points];newPoints[index]=newValue;props.onChangeProps({points:newPoints});}}),points.length>3&&jsxRuntimeExports.jsx(IconButton,{"aria-label":`Delete polygon point ${pointLabel}`,icon:minusCircle,kind:"tertiary",actionType:"destructive",onClick:()=>{const newPoints=[...points];newPoints.splice(index,1);props.onChangeProps({points:newPoints});},style:styles$k.icon})]},`locked-polygon-point-index-${index}`)}),jsxRuntimeExports.jsxs(View,{style:[styles$k.row,styles$k.polygonActionsContainer],children:[jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{props.onChangeProps({points:[...points,[0,0]]});},children:"Add point"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(View,{style:styles$k.movementButtonsContainer,children:[jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon up",size:"small",icon:arrowFatUp,kind:"tertiary",onClick:()=>handlePolygonMove("up")}),jsxRuntimeExports.jsxs(View,{style:styles$k.row,children:[jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon left",size:"small",icon:arrowFatLeft,kind:"tertiary",onClick:()=>handlePolygonMove("left")}),jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon down",size:"small",icon:arrowFatDown,kind:"tertiary",onClick:()=>handlePolygonMove("down")}),jsxRuntimeExports.jsx(IconButton,{"aria-label":"Move polygon right",size:"small",icon:arrowFatRight,kind:"tertiary",onClick:()=>handlePolygonMove("right")})]})]})]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$k.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$k.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$k.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[points[0][0],points[0][1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$k.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$k=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},pointAccordionContainer:{backgroundColor:color.white},pointAccordionPanel:{alignItems:"start"},icon:{marginInlineStart:spacing.xxxSmall_4},polygonActionsContainer:{width:"100%"},movementButtonsContainer:{display:"flex",flexDirection:"column",alignItems:"center",minWidth:"fit-content"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1606
1615
 
1607
- const lengthErrorMessage="The vector cannot have length 0.";const LockedVectorSettings=props=>{const{points,color:lineColor,weight,labels,ariaLabel,onChangeProps,onMove,onRemove}=props;const[tail,tip]=points;const lineLabel=`Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;const isInvalid=vector.equal(tail,tip);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenTailX=await generateSpokenMathDetails(`$${tail[0]}$`);const spokenTailY=await generateSpokenMathDetails(`$${tail[1]}$`);const spokenTipX=await generateSpokenMathDetails(`$${tip[0]}$`);const spokenTipY=await generateSpokenMathDetails(`$${tip[1]}$`);let str=`Vector${visiblelabel} from ${spokenTailX} comma ${spokenTailY} to ${spokenTipX} comma ${spokenTipY}`;const vectorAppearance=generateLockedFigureAppearanceDescription(lineColor,"solid",undefined,weight);str+=vectorAppearance;return str}function handleChangePoint(newCoord,index){if(typeof newCoord!=="undefined"){const newPoints=[...points];newPoints[index]=[...newCoord];const oldMidpoint=vec.midpoint(tail,tip);const newMidpoint=vec.midpoint(newPoints[0],newPoints[1]);const offset=vec.sub(newMidpoint,oldMidpoint);const newLabels=labels.map(label=>({...label,coord:vec.add(label.coord,offset)}));onChangeProps({points:newPoints,labels:newLabels});}}function handleColorChange(newColor){const newProps={color:newColor};newProps.labels=labels.map(label=>({...label,color:newColor}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$k.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:"solid"})]}),children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange,style:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(LabelMedium,{style:styles$k.errorText,children:lengthErrorMessage}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:styles$k.container,panelStyle:styles$k.accordionPanel,header:jsxRuntimeExports.jsx(View,{style:styles$k.row,children:jsxRuntimeExports.jsx(LabelLarge,{children:`Tail (${tail[0]}, ${tail[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tail,error:isInvalid,onChange:newProps=>{handleChangePoint(newProps,0);}})}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:styles$k.container,panelStyle:styles$k.accordionPanel,header:jsxRuntimeExports.jsx(View,{style:styles$k.row,children:jsxRuntimeExports.jsx(LabelLarge,{children:`Tip (${tip[0]}, ${tip[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tip,error:isInvalid,onChange:newProps=>{handleChangePoint(newProps,1);}})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$k.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$k.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$k.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),vec.midpoint(tail,tip));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$k.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$k=StyleSheet.create({accordionPanel:{paddingBottom:spacing.medium_16},container:{marginTop:spacing.xSmall_8,marginBottom:0,marginLeft:-spacing.xxxSmall_4,marginRight:-spacing.xxxSmall_4,backgroundColor:color.white},errorText:{color:color.red,marginTop:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1616
+ const lengthErrorMessage="The vector cannot have length 0.";const LockedVectorSettings=props=>{const{points,color:lineColor,weight,labels,ariaLabel,onChangeProps,onMove,onRemove}=props;const[tail,tip]=points;const lineLabel=`Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;const isInvalid=vector.equal(tail,tip);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenTailX=await generateSpokenMathDetails(`$${tail[0]}$`);const spokenTailY=await generateSpokenMathDetails(`$${tail[1]}$`);const spokenTipX=await generateSpokenMathDetails(`$${tip[0]}$`);const spokenTipY=await generateSpokenMathDetails(`$${tip[1]}$`);let str=`Vector${visiblelabel} from ${spokenTailX} comma ${spokenTailY} to ${spokenTipX} comma ${spokenTipY}`;const vectorAppearance=generateLockedFigureAppearanceDescription(lineColor,"solid",undefined,weight);str+=vectorAppearance;return str}function handleChangePoint(newCoord,index){if(typeof newCoord!=="undefined"){const newPoints=[...points];newPoints[index]=[...newCoord];const oldMidpoint=vec.midpoint(tail,tip);const newMidpoint=vec.midpoint(newPoints[0],newPoints[1]);const offset=vec.sub(newMidpoint,oldMidpoint);const newLabels=labels.map(label=>({...label,coord:vec.add(label.coord,offset)}));onChangeProps({points:newPoints,labels:newLabels});}}function handleColorChange(newColor){const newProps={color:newColor};newProps.labels=labels.map(label=>({...label,color:newColor}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$j.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:lineLabel}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:"solid"})]}),children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,onChange:handleColorChange,style:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(LabelMedium,{style:styles$j.errorText,children:lengthErrorMessage}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:styles$j.container,panelStyle:styles$j.accordionPanel,header:jsxRuntimeExports.jsx(View,{style:styles$j.row,children:jsxRuntimeExports.jsx(LabelLarge,{children:`Tail (${tail[0]}, ${tail[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tail,error:isInvalid,onChange:newProps=>{handleChangePoint(newProps,0);}})}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:styles$j.container,panelStyle:styles$j.accordionPanel,header:jsxRuntimeExports.jsx(View,{style:styles$j.row,children:jsxRuntimeExports.jsx(LabelLarge,{children:`Tip (${tip[0]}, ${tip[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tip,error:isInvalid,onChange:newProps=>{handleChangePoint(newProps,1);}})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$j.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$j.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$j.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),vec.midpoint(tail,tip));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},style:styles$j.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$j=StyleSheet.create({accordionPanel:{paddingBottom:spacing.medium_16},container:{marginTop:spacing.xSmall_8,marginBottom:0,marginLeft:-spacing.xxxSmall_4,marginRight:-spacing.xxxSmall_4,backgroundColor:color.white},errorText:{color:color.red,marginTop:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"},addButton:{alignSelf:"start"},horizontalRule:{height:1,backgroundColor:color.offBlack16},labelContainer:{backgroundColor:color.white}});
1608
1617
 
1609
1618
  const LockedFigureSettings=props=>{switch(props.type){case "point":return jsxRuntimeExports.jsx(LockedPointSettings,{...props});case "line":return jsxRuntimeExports.jsx(LockedLineSettings,{...props});case "vector":return jsxRuntimeExports.jsx(LockedVectorSettings,{...props});case "ellipse":return jsxRuntimeExports.jsx(LockedEllipseSettings,{...props});case "polygon":return jsxRuntimeExports.jsx(LockedPolygonSettings,{...props});case "function":return jsxRuntimeExports.jsx(LockedFunctionSettings,{...props});case "label":return jsxRuntimeExports.jsx(LockedLabelSettings,{...props});default:throw new UnreachableCaseError(props)}};
1610
1619
 
1611
- const LockedFiguresSection=props=>{const collapsedStateArray=Array((props.figures??[]).length).fill(false);const[expandedStates,setExpandedStates]=React.useState(collapsedStateArray);const[isExpanded,setIsExpanded]=React.useState(true);const uniqueId=useId();const{figures,onChange}=props;function addLockedFigure(newFigure){const lockedFigures=figures||[];const newProps={lockedFigures:[...lockedFigures,getDefaultFigureForType(newFigure)]};onChange(newProps);setExpandedStates([...expandedStates,true]);}function moveLockedFigure(index,movement){if(index===0&&(movement==="back"||movement==="backward")){return}if(figures&&index===figures.length-1&&(movement==="front"||movement==="forward")){return}const lockedFigures=figures||[];const newFigures=[...lockedFigures];const newExpandedStates=[...expandedStates];const[removedFigure]=newFigures.splice(index,1);newExpandedStates.splice(index,1);switch(movement){case "back":newFigures.unshift(removedFigure);newExpandedStates.unshift(true);break;case "backward":newFigures.splice(index-1,0,removedFigure);newExpandedStates.splice(index-1,0,true);break;case "forward":newFigures.splice(index+1,0,removedFigure);newExpandedStates.splice(index+1,0,true);break;case "front":newFigures.push(removedFigure);newExpandedStates.push(true);break}onChange({lockedFigures:newFigures});setExpandedStates(newExpandedStates);}function removeLockedFigure(index){if(window.confirm("Are you sure you want to delete this figure?")){const lockedFigures=figures||[];onChange({lockedFigures:[...lockedFigures.slice(0,index),...lockedFigures.slice(index+1)]});const newExpandedStates=[...expandedStates];newExpandedStates.splice(index,1);setExpandedStates(newExpandedStates);}}function changeProps(index,figureProps){const lockedFigures=figures||[];const newFigures={lockedFigures:[...lockedFigures.slice(0,index),{...lockedFigures[index],...figureProps},...lockedFigures.slice(index+1)]};onChange(newFigures);}function toggleExpanded(newValue){setExpandedStates(Array(figures?.length).fill(newValue));}const allCollapsed=expandedStates.every(value=>!value);const buttonLabel=allCollapsed?"Expand all":"Collapse all";const showExpandButton=!!figures?.length;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Locked Figures",isOpen:isExpanded,onToggle:()=>setIsExpanded(!isExpanded),isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(View,{children:[figures?.map((figure,index)=>{return jsxRuntimeExports.jsx(LockedFigureSettings,{expanded:expandedStates[index],onToggle:newValue=>{const newExpanded=[...expandedStates];newExpanded[index]=newValue;setExpandedStates(newExpanded);},...figure,onChangeProps:newProps=>changeProps(index,newProps),onMove:movement=>moveLockedFigure(index,movement),onRemove:()=>removeLockedFigure(index)},`${uniqueId}-locked-${figure}-${index}`)}),jsxRuntimeExports.jsxs(View,{style:styles$j.buttonContainer,children:[jsxRuntimeExports.jsx(LockedFigureSelect,{id:`${uniqueId}-select`,onChange:addLockedFigure}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),showExpandButton&&jsxRuntimeExports.jsx(Button,{kind:"secondary",onClick:()=>toggleExpanded(allCollapsed),style:styles$j.button,children:buttonLabel})]})]})]})};const styles$j=StyleSheet.create({buttonContainer:{flexDirection:"row",alignItems:"center"},button:{marginTop:spacing.xSmall_8,flexGrow:1}});
1620
+ const LockedFiguresSection=props=>{const collapsedStateArray=Array((props.figures??[]).length).fill(false);const[expandedStates,setExpandedStates]=React.useState(collapsedStateArray);const[isExpanded,setIsExpanded]=React.useState(true);const uniqueId=useId();const{figures,onChange}=props;function addLockedFigure(newFigure){const lockedFigures=figures||[];const newProps={lockedFigures:[...lockedFigures,getDefaultFigureForType(newFigure)]};onChange(newProps);setExpandedStates([...expandedStates,true]);}function moveLockedFigure(index,movement){if(index===0&&(movement==="back"||movement==="backward")){return}if(figures&&index===figures.length-1&&(movement==="front"||movement==="forward")){return}const lockedFigures=figures||[];const newFigures=[...lockedFigures];const newExpandedStates=[...expandedStates];const[removedFigure]=newFigures.splice(index,1);newExpandedStates.splice(index,1);switch(movement){case "back":newFigures.unshift(removedFigure);newExpandedStates.unshift(true);break;case "backward":newFigures.splice(index-1,0,removedFigure);newExpandedStates.splice(index-1,0,true);break;case "forward":newFigures.splice(index+1,0,removedFigure);newExpandedStates.splice(index+1,0,true);break;case "front":newFigures.push(removedFigure);newExpandedStates.push(true);break}onChange({lockedFigures:newFigures});setExpandedStates(newExpandedStates);}function removeLockedFigure(index){if(window.confirm("Are you sure you want to delete this figure?")){const lockedFigures=figures||[];onChange({lockedFigures:[...lockedFigures.slice(0,index),...lockedFigures.slice(index+1)]});const newExpandedStates=[...expandedStates];newExpandedStates.splice(index,1);setExpandedStates(newExpandedStates);}}function changeProps(index,figureProps){const lockedFigures=figures||[];const newFigures={lockedFigures:[...lockedFigures.slice(0,index),{...lockedFigures[index],...figureProps},...lockedFigures.slice(index+1)]};onChange(newFigures);}function toggleExpanded(newValue){setExpandedStates(Array(figures?.length).fill(newValue));}const allCollapsed=expandedStates.every(value=>!value);const buttonLabel=allCollapsed?"Expand all":"Collapse all";const showExpandButton=!!figures?.length;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Locked Figures",isOpen:isExpanded,onToggle:()=>setIsExpanded(!isExpanded),isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(View,{children:[figures?.map((figure,index)=>{return jsxRuntimeExports.jsx(LockedFigureSettings,{expanded:expandedStates[index],onToggle:newValue=>{const newExpanded=[...expandedStates];newExpanded[index]=newValue;setExpandedStates(newExpanded);},...figure,onChangeProps:newProps=>changeProps(index,newProps),onMove:movement=>moveLockedFigure(index,movement),onRemove:()=>removeLockedFigure(index)},`${uniqueId}-locked-${figure}-${index}`)}),jsxRuntimeExports.jsxs(View,{style:styles$i.buttonContainer,children:[jsxRuntimeExports.jsx(LockedFigureSelect,{id:`${uniqueId}-select`,onChange:addLockedFigure}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),showExpandButton&&jsxRuntimeExports.jsx(Button,{kind:"secondary",onClick:()=>toggleExpanded(allCollapsed),style:styles$i.button,children:buttonLabel})]})]})]})};const styles$i=StyleSheet.create({buttonContainer:{flexDirection:"row",alignItems:"center"},button:{marginTop:spacing.xSmall_8,flexGrow:1}});
1612
1621
 
1613
1622
  const{getClockwiseAngle}=angles;function getStartCoords(graph){if("startCoords"in graph){return graph.startCoords}return undefined}function getDefaultGraphStartCoords(graph,range,step){switch(graph.type){case "linear":case "ray":return getLineCoords({...graph,startCoords:undefined},range,step);case "segment":return getSegmentCoords({...graph,startCoords:undefined},range,step);case "linear-system":return getLinearSystemCoords({...graph,startCoords:undefined},range,step);case "circle":const startCoords=getCircleCoords({...graph,startCoords:undefined});const radius=vector.length(vector.subtract(startCoords.radiusPoint,startCoords.center));return {center:startCoords.center,radius};case "sinusoid":return getSinusoidCoords({...graph,startCoords:undefined},range,step);case "quadratic":return getQuadraticCoords({...graph,startCoords:undefined},range,step);case "point":return getPointCoords({...graph,startCoords:undefined},range,step);case "polygon":return getPolygonCoords({...graph,startCoords:undefined},range,step);case "angle":return getAngleCoords({graph:{...graph,startCoords:undefined},range,step});default:return undefined}}const getSinusoidEquation=startCoords=>{const p1=startCoords[0];const p2=startCoords[1];const amplitude=p2[1]-p1[1];const angularFrequency=Math.PI/(2*(p2[0]-p1[0]));const phase=p1[0]*angularFrequency;const verticalOffset=p1[1];return "y = "+amplitude.toFixed(3)+"sin("+angularFrequency.toFixed(3)+"x - "+phase.toFixed(3)+") + "+verticalOffset.toFixed(3)};const getQuadraticEquation=startCoords=>{const p1=startCoords[0];const p2=startCoords[1];const p3=startCoords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return "Division by zero error"}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 "y = "+a.toFixed(3)+"x^2 + "+b.toFixed(3)+"x + "+c.toFixed(3)};const getAngleEquation=(startCoords,allowReflexAngles=false)=>{const vertex=startCoords[1];const roundedAngle=getClockwiseAngle(startCoords,allowReflexAngles).toFixed(0);return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`};const shouldShowStartCoordsUI=(graph,isStatic)=>{if(isStatic){return false}switch(graph.type){case "point":return graph.numPoints!=="unlimited";case "polygon":return graph.numSides!=="unlimited"&&graph.snapTo!=="angles"&&graph.snapTo!=="sides";case "none":return false;case "angle":case "circle":case "linear":case "linear-system":case "quadratic":case "ray":case "segment":case "sinusoid":return true;default:throw new UnreachableCaseError(graph)}};
1614
1623
 
1615
- const StartCoordsAngle=props=>{const{startCoords,allowReflexAngles,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$i.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$i.equationBody,children:getAngleEquation(startCoords,allowReflexAngles)})]}),jsxRuntimeExports.jsxs(View,{style:styles$i.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1],startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$i.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Vertex:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value,startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$i.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[2],labels:["x","y"],onChange:value=>onChange([startCoords[0],startCoords[1],value])})]})]})};const styles$i=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1624
+ const StartCoordsAngle=props=>{const{startCoords,allowReflexAngles,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$h.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$h.equationBody,children:getAngleEquation(startCoords,allowReflexAngles)})]}),jsxRuntimeExports.jsxs(View,{style:styles$h.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1],startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$h.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Vertex:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value,startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$h.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[2],labels:["x","y"],onChange:value=>onChange([startCoords[0],startCoords[1],value])})]})]})};const styles$h=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1616
1625
 
1617
- const StartCoordsCircle=props=>{const{startCoords,onChange}=props;const[radiusState,setRadiusState]=React.useState(startCoords.radius.toString());React.useEffect(()=>{setRadiusState(startCoords.radius.toString());},[startCoords.radius]);function handleRadiuschange(newValue){setRadiusState(newValue);if(isNaN(+newValue)||newValue===""||+newValue===0){return}onChange({center:startCoords.center,radius:parseFloat(newValue)});}return jsxRuntimeExports.jsxs(View,{style:styles$h.tile,children:[jsxRuntimeExports.jsxs(View,{style:styles$h.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Center:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords.center,labels:["x","y"],onChange:coord=>onChange({center:coord,radius:startCoords.radius})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",style:styles$h.row,children:["Radius:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:radiusState,onChange:handleRadiuschange,style:styles$h.textField})]})]})};const styles$h=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
1626
+ const StartCoordsCircle=props=>{const{startCoords,onChange}=props;const[radiusState,setRadiusState]=React.useState(startCoords.radius.toString());React.useEffect(()=>{setRadiusState(startCoords.radius.toString());},[startCoords.radius]);function handleRadiuschange(newValue){setRadiusState(newValue);if(isNaN(+newValue)||newValue===""||+newValue===0){return}onChange({center:startCoords.center,radius:parseFloat(newValue)});}return jsxRuntimeExports.jsxs(View,{style:styles$g.tile,children:[jsxRuntimeExports.jsxs(View,{style:styles$g.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Center:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords.center,labels:["x","y"],onChange:coord=>onChange({center:coord,radius:startCoords.radius})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",style:styles$g.row,children:["Radius:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:radiusState,onChange:handleRadiuschange,style:styles$g.textField})]})]})};const styles$g=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
1618
1627
 
1619
- const StartCoordsLine=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$g.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$g.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value])})]})]})};const styles$g=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"}});
1628
+ const StartCoordsLine=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$f.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$f.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value])})]})]})};const styles$f=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"}});
1620
1629
 
1621
- const StartCoordsMultiline=props=>{const{startCoords,type,onChange}=props;const graphName=type==="segment"?"Segment":"Line";return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:startCoords.map((coordPair,i)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:`${graphName} ${i+1}`}),expanded:true,children:[jsxRuntimeExports.jsxs(View,{style:styles$f.nestedTile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coordPair[0],labels:["x","y"],onChange:value=>{const newCoords=[...startCoords];newCoords[i]=[value,coordPair[1]];onChange(newCoords);}})]}),jsxRuntimeExports.jsxs(View,{style:styles$f.nestedTile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coordPair[1],labels:["x","y"],onChange:value=>{const newCoords=[...startCoords];newCoords[i]=[coordPair[0],value];onChange(newCoords);}})]})]},`segment-${i}-start-coords`))})};const styles$f=StyleSheet.create({nestedTile:{paddingBottom:spacing.small_12,flexDirection:"row",alignItems:"center"}});
1630
+ const StartCoordsMultiline=props=>{const{startCoords,type,onChange}=props;const graphName=type==="segment"?"Segment":"Line";return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:startCoords.map((coordPair,i)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(LabelLarge,{children:`${graphName} ${i+1}`}),expanded:true,children:[jsxRuntimeExports.jsxs(View,{style:styles$e.nestedTile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coordPair[0],labels:["x","y"],onChange:value=>{const newCoords=[...startCoords];newCoords[i]=[value,coordPair[1]];onChange(newCoords);}})]}),jsxRuntimeExports.jsxs(View,{style:styles$e.nestedTile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coordPair[1],labels:["x","y"],onChange:value=>{const newCoords=[...startCoords];newCoords[i]=[coordPair[0],value];onChange(newCoords);}})]})]},`segment-${i}-start-coords`))})};const styles$e=StyleSheet.create({nestedTile:{paddingBottom:spacing.small_12,flexDirection:"row",alignItems:"center"}});
1622
1631
 
1623
- const StartCoordsPoint=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:startCoords.map((coord,index)=>{return jsxRuntimeExports.jsxs(View,{style:styles$e.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Point ${index+1}:`}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,labels:["x","y"],onChange:newCoord=>{const newStartCoords=[...startCoords];newStartCoords[index]=newCoord;onChange(newStartCoords);}})]},index)})})};const styles$e=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"}});
1632
+ const StartCoordsPoint=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:startCoords.map((coord,index)=>{return jsxRuntimeExports.jsxs(View,{style:styles$d.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Point ${index+1}:`}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,labels:["x","y"],onChange:newCoord=>{const newStartCoords=[...startCoords];newStartCoords[index]=newCoord;onChange(newStartCoords);}})]},index)})})};const styles$d=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"}});
1624
1633
 
1625
- const StartCoordsQuadratic=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$d.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$d.equationBody,children:getQuadraticEquation(startCoords)})]}),jsxRuntimeExports.jsxs(View,{style:styles$d.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1],startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$d.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value,startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$d.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 3:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[2],labels:["x","y"],onChange:value=>onChange([startCoords[0],startCoords[1],value])})]})]})};const styles$d=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1634
+ const StartCoordsQuadratic=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$c.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$c.equationBody,children:getQuadraticEquation(startCoords)})]}),jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1],startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value,startCoords[2]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 3:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[2],labels:["x","y"],onChange:value=>onChange([startCoords[0],startCoords[1],value])})]})]})};const styles$c=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1626
1635
 
1627
- const StartCoordsSinusoid=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$c.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$c.equationBody,children:getSinusoidEquation(startCoords)})]}),jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value])})]})]})};const styles$c=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1636
+ const StartCoordsSinusoid=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$b.equationSection,children:[jsxRuntimeExports.jsx(LabelMedium,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$b.equationBody,children:getSinusoidEquation(startCoords)})]}),jsxRuntimeExports.jsxs(View,{style:styles$b.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$b.tile,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value])})]})]})};const styles$b=StyleSheet.create({tile:{backgroundColor:color.fadedBlue8,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"},equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:color.fadedOffBlack8,border:`1px solid ${color.fadedOffBlack32}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.xSmall}});
1628
1637
 
1629
1638
  const StartCoordsSettingsInner=props=>{const{type,range,step,allowReflexAngles,onChange}=props;switch(type){case "linear":case "ray":const linearCoords=getLineCoords(props,range,step);return jsxRuntimeExports.jsx(StartCoordsLine,{startCoords:linearCoords,onChange:onChange});case "linear-system":case "segment":const multiLineCoords=type==="segment"?getSegmentCoords(props,range,step):getLinearSystemCoords(props,range,step);return jsxRuntimeExports.jsx(StartCoordsMultiline,{type:type,startCoords:multiLineCoords,onChange:onChange});case "circle":const circleCoords=getCircleCoords(props);const radius=vector.length(vector.subtract(circleCoords.radiusPoint,circleCoords.center));return jsxRuntimeExports.jsx(StartCoordsCircle,{startCoords:{center:circleCoords.center,radius},onChange:onChange});case "sinusoid":const sinusoidCoords=getSinusoidCoords(props,range,step);return jsxRuntimeExports.jsx(StartCoordsSinusoid,{startCoords:sinusoidCoords,onChange:onChange});case "quadratic":const quadraticCoords=getQuadraticCoords(props,range,step);return jsxRuntimeExports.jsx(StartCoordsQuadratic,{startCoords:quadraticCoords,onChange:onChange});case "point":case "polygon":const pointCoords=type==="point"?getPointCoords(props,range,step):getPolygonCoords(props,range,step);return jsxRuntimeExports.jsx(StartCoordsPoint,{startCoords:pointCoords,onChange:onChange});case "angle":const angleCoords=getAngleCoords({graph:props,range,step});return jsxRuntimeExports.jsx(StartCoordsAngle,{startCoords:angleCoords,allowReflexAngles:allowReflexAngles,onChange:onChange});default:return null}};const StartCoordsSettings=props=>{const{range,step,onChange}=props;const[isOpen,setIsOpen]=React.useState(true);return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(Heading,{isCollapsible:true,title:"Start coordinates",isOpen:isOpen,onToggle:()=>setIsOpen(!isOpen)}),isOpen&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(StartCoordsSettingsInner,{...props}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{startIcon:arrowCounterClockwise,kind:"tertiary",size:"small",onClick:()=>{onChange(getDefaultGraphStartCoords(props,range,step));},children:"Use default start coordinates"})]})]})};
1630
1639
 
1631
- const{InfoTip: InfoTip$b}=components;const InteractiveGraph=InteractiveGraphWidget.widget;const POLYGON_SIDES=_.map(_.range(3,13),function(value){return jsxRuntimeExports.jsx(OptionItem,{value:`${value}`,label:`${value} sides`},`polygon-sides-${value}`)});class InteractiveGraphEditor extends React.Component{serialize(){const json=_.pick(this.props,"step","backgroundImage","markings","labels","labelLocation","showProtractor","showTooltips","range","gridStep","snapStep","lockedFigures","fullGraphAriaLabel","fullGraphAriaDescription");const graph=this.refs.graph;if(graph){const correct=graph&&graph.getUserInput();_.extend(json,{graph:{type:correct.type,startCoords:this.props.graph&&getStartCoords(this.props.graph)},correct:correct});_.each(["allowReflexAngles","angleOffsetDeg","numPoints","numSides","numSegments","showAngles","showSides","snapTo","snapDegrees"],function(key){if(_.has(correct,key)){json.graph[key]=correct[key];}});}return json}render(){let graph;let equationString;const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,interactiveSizes.defaultBoxSize);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const sizeClass=containerSizeClass.SMALL;if(this.props.valid===true){const correct=this.props.correct;const graphProps={ref:"graph",box:this.props.box,range:this.props.range,labels:this.props.labels,labelLocation:this.props.labelLocation,step:this.props.step,gridStep:gridStep,snapStep:snapStep,backgroundImage:this.props.backgroundImage,markings:this.props.markings,showProtractor:this.props.showProtractor,showTooltips:this.props.showTooltips,lockedFigures:this.props.lockedFigures,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,trackInteraction:function(){},userInput:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(correct.type===newGraph.type){correct=mergeGraphs(correct,newGraph);}else {correct=newGraph;}this.props.onChange({correct:correct,graph:this.props.graph});}};graph=jsxRuntimeExports.jsx(InteractiveGraph,{...graphProps,containerSizeClass:sizeClass,apiOptions:{...this.props.apiOptions,isMobile:false}});equationString=InteractiveGraph.getEquationString(graphProps);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.valid});}return jsxRuntimeExports.jsx(Id,{children:graphId=>jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Answer type:",children:jsxRuntimeExports.jsx(GraphTypeSelector,{graphType:this.props.graph?.type??InteractiveGraph.defaultProps.userInput.type,onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",onChange:this.props.onChange}),jsxRuntimeExports.jsx(InteractiveGraphCorrectAnswer,{id:graphId,equationString:equationString,children:graph}),this.props.correct?.type==="point"&&jsxRuntimeExports.jsx(LabeledRow,{label:"Number of Points:",children:jsxRuntimeExports.jsx(GraphPointsCountSelector,{numPoints:this.props.correct?.numPoints,onChange:points=>{this.props.onChange({correct:{type:"point",numPoints:points},graph:{type:"point",numPoints:points}});}})}),this.props.correct?.type==="angle"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$b.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!this.props.correct?.showAngles,onChange:newValue=>{if(this.props.graph?.type==="angle"){invariant(this.props.correct.type==="angle",`Expected graph type to be angle, but got ${this.props.correct.type}`);this.props.onChange({correct:{...this.props.correct,showAngles:newValue},graph:{...this.props.graph,showAngles:newValue}});}}}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{style:styles$b.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Allow reflex angles"}),checked:!!this.props.correct?.allowReflexAngles,onChange:newValue=>{invariant(this.props.correct.type==="angle",`Expected graph type to be angle, but got ${this.props.correct.type}`);invariant(this.props.graph?.type==="angle",`Expected graph type to be angle, but got ${this.props.graph?.type}`);const update={allowReflexAngles:newValue};this.props.onChange({correct:{...this.props.correct,...update},graph:{...this.props.graph,...update}});}}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsx("p",{children:"Allow students to be able to create reflex angles."})})]})]}),this.props.correct?.type==="polygon"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Number of sides:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:this.props.correct?.numSides?`${this.props.correct.numSides}`:"3",placeholder:"",onChange:newValue=>{invariant(this.props.graph?.type==="polygon");const updates={numSides:parsePointCount(newValue),coords:undefined,startCoords:undefined,snapTo:"grid"};this.props.onChange({correct:{...this.props.correct,...updates},graph:{...this.props.graph,...updates}});},style:styles$b.singleSelectShort,children:[...POLYGON_SIDES,jsxRuntimeExports.jsx(OptionItem,{value:"unlimited",label:"unlimited sides"},"unlimited")]},"polygon-select")}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Snap to:",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:this.props.correct?.snapTo||"grid",placeholder:"",onChange:newValue=>{invariant(this.props.correct.type==="polygon",`Expected correct answer type to be polygon, but got ${this.props.correct.type}`);invariant(this.props.graph?.type==="polygon",`Expected graph type to be polygon, but got ${this.props.graph?.type}`);const updates={snapTo:newValue,coords:null};this.props.onChange({correct:{...this.props.correct,...updates},graph:{...this.props.graph,...updates}});},style:styles$b.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"grid",label:"grid"}),this.props.correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"angles",label:"interior angles"}),this.props.correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"sides",label:"side measures"})]}),jsxRuntimeExports.jsxs(InfoTip$b,{children:[jsxRuntimeExports.jsx("p",{children:"These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."}),jsxRuntimeExports.jsx("p",{children:"The interior angle and side measure options guide the points to the nearest whole angle or side measure respectively."})]})]}),jsxRuntimeExports.jsxs(View,{style:styles$b.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!this.props.correct?.showAngles,onChange:()=>{if(this.props.graph?.type==="polygon"){invariant(this.props.correct.type==="polygon",`Expected graph type to be polygon, but got ${this.props.correct.type}`);this.props.onChange({correct:{...this.props.correct,showAngles:!this.props.correct.showAngles},graph:{...this.props.graph,showAngles:!this.props.graph.showAngles}});}}}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{style:styles$b.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show side measures"}),checked:!!this.props.correct?.showSides,onChange:()=>{if(this.props.graph?.type==="polygon"&&this.props.correct.type==="polygon"){this.props.onChange({correct:{...this.props.correct,showSides:!this.props.correct.showSides},graph:{...this.props.graph,showSides:!this.props.graph.showSides}});}}}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsx("p",{children:"Displays the side lengths."})})]})]}),this.props.correct?.type==="segment"&&jsxRuntimeExports.jsx(LabeledRow,{label:"Number of segments:",children:jsxRuntimeExports.jsx(SegmentCountSelector,{numSegments:this.props.correct?.numSegments,onChange:sides=>{this.props.onChange({correct:{type:"segment",numSegments:sides,coords:null},graph:{type:"segment",numSegments:sides}});}})}),this.props.graph?.type&&shouldShowStartCoordsUI(this.props.graph,this.props.static)&&jsxRuntimeExports.jsx(StartCoordsSettings,{...this.props.graph,range:this.props.range,step:this.props.step,onChange:this.changeStartCoords}),jsxRuntimeExports.jsx(InteractiveGraphSRTree,{graphId:graphId,correct:this.props.correct,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,lockedFigures:this.props.lockedFigures}),jsxRuntimeExports.jsx(InteractiveGraphSettings,{box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.range,labels:this.props.labels,labelLocation:this.props.labelLocation,step:this.props.step,gridStep:gridStep,snapStep:snapStep,valid:this.props.valid,backgroundImage:this.props.backgroundImage,markings:this.props.markings,showProtractor:this.props.showProtractor,showTooltips:this.props.showTooltips,onChange:this.props.onChange}),this.props.correct.type==="polygon"&&jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:this.props.correct.match||"exact",onChange:newValue=>{invariant(this.props.correct.type==="polygon",`Expected graph type to be polygon, but got ${this.props.correct.type}`);const correct={...this.props.correct,match:newValue};this.props.onChange({correct});},placeholder:"",style:styles$b.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"approx",label:"be approximately congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"similar",label:"be similar"})]}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsxs("ul",{children:[jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Match Exactly:"})," Match exactly in size, orientation, and location on the grid even if it is not shown in the background."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Congruent:"})," Be congruent in size and shape, but can be located anywhere on the grid."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Approximately Congruent:"})," ","Be exactly similar, and congruent in size and shape to within 0.1 units, but can be located anywhere on the grid."," ",jsxRuntimeExports.jsx("em",{children:"Use this with snapping to angle measure."})]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Similar:"})," Be similar with matching interior angles, and side measures that are matching or a multiple of the correct side measures. The figure can be located anywhere on the grid."]})})]})})]}),this.props.correct.type==="angle"&&jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:this.props.correct.match||"exact",onChange:newValue=>{invariant(this.props.correct.type==="angle",`Expected graph type to be angle, but got ${this.props.correct.type}`);this.props.onChange({correct:{...this.props.correct,match:newValue}});},placeholder:"",style:styles$b.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"})]}),jsxRuntimeExports.jsx(InfoTip$b,{children:jsxRuntimeExports.jsx("p",{children:"Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position."})})]}),jsxRuntimeExports.jsx(LockedFiguresSection,{figures:this.props.lockedFigures,onChange:this.props.onChange})]})})}constructor(...args){super(...args),this.displayName="InteractiveGraphEditor",this.className="perseus-widget-interactive-graph",this.changeStartCoords=coords=>{if(!this.props.graph?.type){return}const graph={...this.props.graph,startCoords:coords};this.props.onChange({graph:graph});},this.getSaveWarnings=()=>{const issues=[];for(const figure of this.props.lockedFigures??[]){if(figure.type==="line"&&vector.equal(figure.points[0].coord,figure.points[1].coord)){issues.push("The line cannot have length 0.");}}if(this.props.graph?.type==="polygon"&&this.props.graph.numSides==="unlimited"&&this.props.graph.coords===null){issues.push("Polygon must be closed.");}return issues};}}InteractiveGraphEditor.widgetName="interactive-graph";InteractiveGraphEditor.defaultProps={...interactiveGraphLogic.defaultWidgetOptions,valid:true,lockedFigures:[]};function mergeGraphs(a,b){if(a.type!==b.type){throw new Error(`Cannot merge graphs with different types (${a.type} and ${b.type})`)}switch(a.type){case "angle":invariant(b.type==="angle");return {...a,...b};case "circle":invariant(b.type==="circle");return {...a,...b};case "linear":invariant(b.type==="linear");return {...a,...b};case "linear-system":invariant(b.type==="linear-system");return {...a,...b};case "none":invariant(b.type==="none");return {...a,...b};case "point":invariant(b.type==="point");return {...a,...b};case "polygon":invariant(b.type==="polygon");return {...a,...b};case "quadratic":invariant(b.type==="quadratic");return {...a,...b};case "ray":invariant(b.type==="ray");return {...a,...b};case "segment":invariant(b.type==="segment");return {...a,...b};case "sinusoid":invariant(b.type==="sinusoid");return {...a,...b};default:throw new UnreachableCaseError(a)}}const styles$b=StyleSheet.create({singleSelectShort:{height:26},row:{flexDirection:"row",marginTop:spacing.xSmall_8,alignItems:"center"}});
1640
+ const InteractiveGraph=InteractiveGraphWidget.widget;class InteractiveGraphEditor extends React.Component{serialize(){const json=_.pick(this.props,"step","backgroundImage","markings","labels","labelLocation","showProtractor","showTooltips","range","gridStep","snapStep","lockedFigures","fullGraphAriaLabel","fullGraphAriaDescription");const graph=this.refs.graph;if(graph){const correct=graph&&graph.getUserInput();_.extend(json,{graph:{type:correct.type,startCoords:this.props.graph&&getStartCoords(this.props.graph)},correct:correct});_.each(["allowReflexAngles","angleOffsetDeg","numPoints","numSides","numSegments","showAngles","showSides","snapTo","snapDegrees"],function(key){if(_.has(correct,key)){json.graph[key]=correct[key];}});}return json}render(){let graph;let equationString;const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,interactiveSizes.defaultBoxSize);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const sizeClass=containerSizeClass.SMALL;if(this.props.valid===true){const correct=this.props.correct;const graphProps={ref:"graph",box:this.props.box,range:this.props.range,labels:this.props.labels,labelLocation:this.props.labelLocation,step:this.props.step,gridStep:gridStep,snapStep:snapStep,backgroundImage:this.props.backgroundImage,markings:this.props.markings,showProtractor:this.props.showProtractor,showTooltips:this.props.showTooltips,lockedFigures:this.props.lockedFigures,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,trackInteraction:function(){},userInput:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(correct.type===newGraph.type){correct=mergeGraphs(correct,newGraph);}else {correct=newGraph;}this.props.onChange({correct:correct,graph:this.props.graph});}};graph=jsxRuntimeExports.jsx(InteractiveGraph,{...graphProps,containerSizeClass:sizeClass,apiOptions:{...this.props.apiOptions,isMobile:false}});equationString=InteractiveGraph.getEquationString(graphProps);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.valid});}return jsxRuntimeExports.jsx(Id,{children:graphId=>jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Answer type:",children:jsxRuntimeExports.jsx(GraphTypeSelector,{graphType:this.props.graph?.type??InteractiveGraph.defaultProps.userInput.type,onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",onChange:this.props.onChange}),jsxRuntimeExports.jsx(InteractiveGraphCorrectAnswer,{id:graphId,equationString:equationString,children:graph}),this.props.correct?.type==="angle"&&jsxRuntimeExports.jsx(AngleAnswerOptions,{correct:this.props.correct,graph:this.props.graph,onChange:this.props.onChange}),this.props.correct?.type==="point"&&jsxRuntimeExports.jsx(GraphPointsCountSelector,{correct:this.props.correct,graph:this.props.graph,onChange:this.props.onChange}),this.props.correct?.type==="polygon"&&jsxRuntimeExports.jsx(PolygonAnswerOptions,{correct:this.props.correct,graph:this.props.graph,onChange:this.props.onChange}),this.props.correct?.type==="segment"&&jsxRuntimeExports.jsx(SegmentCountSelector,{correct:this.props.correct,graph:this.props.graph,onChange:this.props.onChange}),this.props.graph?.type&&shouldShowStartCoordsUI(this.props.graph,this.props.static)&&jsxRuntimeExports.jsx(StartCoordsSettings,{...this.props.graph,range:this.props.range,step:this.props.step,onChange:this.changeStartCoords}),jsxRuntimeExports.jsx(InteractiveGraphSRTree,{graphId:graphId,correct:this.props.correct,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,lockedFigures:this.props.lockedFigures}),jsxRuntimeExports.jsx(InteractiveGraphSettings,{box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.range,labels:this.props.labels,labelLocation:this.props.labelLocation,step:this.props.step,gridStep:gridStep,snapStep:snapStep,valid:this.props.valid,backgroundImage:this.props.backgroundImage,markings:this.props.markings,showProtractor:this.props.showProtractor,showTooltips:this.props.showTooltips,onChange:this.props.onChange}),jsxRuntimeExports.jsx(LockedFiguresSection,{figures:this.props.lockedFigures,onChange:this.props.onChange})]})})}constructor(...args){super(...args),this.displayName="InteractiveGraphEditor",this.className="perseus-widget-interactive-graph",this.changeStartCoords=coords=>{if(!this.props.graph?.type){return}const graph={...this.props.graph,startCoords:coords};this.props.onChange({graph:graph});},this.getSaveWarnings=()=>{const issues=[];for(const figure of this.props.lockedFigures??[]){if(figure.type==="line"&&vector.equal(figure.points[0].coord,figure.points[1].coord)){issues.push("The line cannot have length 0.");}}if(this.props.graph?.type==="polygon"&&this.props.graph.numSides==="unlimited"&&this.props.graph.coords===null){issues.push("Polygon must be closed.");}return issues};}}InteractiveGraphEditor.widgetName="interactive-graph";InteractiveGraphEditor.defaultProps={...interactiveGraphLogic.defaultWidgetOptions,valid:true,lockedFigures:[]};function mergeGraphs(a,b){if(a.type!==b.type){throw new Error(`Cannot merge graphs with different types (${a.type} and ${b.type})`)}switch(a.type){case "angle":invariant(b.type==="angle");return {...a,...b};case "circle":invariant(b.type==="circle");return {...a,...b};case "linear":invariant(b.type==="linear");return {...a,...b};case "linear-system":invariant(b.type==="linear-system");return {...a,...b};case "none":invariant(b.type==="none");return {...a,...b};case "point":invariant(b.type==="point");return {...a,...b};case "polygon":invariant(b.type==="polygon");return {...a,...b};case "quadratic":invariant(b.type==="quadratic");return {...a,...b};case "ray":invariant(b.type==="ray");return {...a,...b};case "segment":invariant(b.type==="segment");return {...a,...b};case "sinusoid":invariant(b.type==="sinusoid");return {...a,...b};default:throw new UnreachableCaseError(a)}}
1632
1641
 
1633
1642
  const gray98="#FAFAFA";const gray95="#F0F1F2";const gray85="#D6D8DA";const gray76="#BABEC2";const gray68="#888D93";const gray41="#626569";const gray17="#21242C";
1634
1643
 
@@ -1687,9 +1696,14 @@ const{InfoTip: InfoTip$3,NumberInput: NumberInput$2,RangeInput,TextListEditor: T
1687
1696
 
1688
1697
  const{NumberInput: NumberInput$1,TextInput}=components;function validateOptions(height,programID){const errors=[];if(programID===""){errors.push("The program ID is required.");}if(!Number.isInteger(height)||height<1){errors.push("The height must be a positive integer.");}return errors}class PythonProgramEditor extends React.Component{serialize(){return {programID:this.props.programID,height:this.props.height}}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["User Program ID:"," ",jsxRuntimeExports.jsx(TextInput,{value:this.props.programID,onChange:this.change("programID"),placeholder:"123"})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Height:"," ",jsxRuntimeExports.jsx(NumberInput$1,{value:this.props.height,onChange:this.change("height"),placeholder:"400"})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.getSaveWarnings=()=>{return validateOptions(this.props.height,this.props.programID)};}}PythonProgramEditor.widgetName="python-program";PythonProgramEditor.defaultProps=pythonProgramLogic.defaultWidgetOptions;
1689
1698
 
1690
- const AutoResizingTextArea=props=>{const textAreaRef=React.useRef(null);React.useEffect(()=>{const textArea=textAreaRef.current;if(textArea){textArea.style.height="42px";textArea.style.height=`${textArea.scrollHeight}px`;}},[props.value]);return jsxRuntimeExports.jsx(TextArea,{...props,ref:textAreaRef,resizeType:"none",style:{overflow:"hidden",...props.style}})};
1699
+ var styles = {"tile":"perseus_fAVMAcnB","radioOptionActionsContainer":"perseus_qMTuHJ53","buttonRow":"perseus_FUUSHyqm","imageEditorContainer":"perseus_JUItwJjV"};
1700
+
1701
+ function RadioImageEditor({initialImageUrl,initialImageAltText,containerClassName,onSave,onClose,onDelete}){const[imageUrl,setImageUrl]=React.useState(initialImageUrl);const[imageAltText,setImageAltText]=React.useState(initialImageAltText);React.useEffect(()=>{setImageUrl(initialImageUrl??"");setImageAltText(initialImageAltText??"");},[initialImageUrl,initialImageAltText]);const uniqueId=React.useId();const imageUrlTextAreaId=`${uniqueId}-image-url-textarea`;const imageAltTextTextAreaId=`${uniqueId}-image-alt-text-textarea`;function handleClose(){setImageUrl("");setImageAltText("");onClose?.();}function handleSave(){onSave(imageUrl,imageAltText);handleClose();}return jsxRuntimeExports.jsxs("div",{className:containerClassName,children:[onClose&&jsxRuntimeExports.jsx(IconButton,{"aria-label":"Close",icon:xIcon,size:"small",kind:"tertiary",onClick:handleClose,style:{position:"absolute",top:4,right:4}}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageUrlTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image URL"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:imageUrlTextAreaId,value:imageUrl,placeholder:"cdn.kastatic.org/...",onChange:value=>{setImageUrl(value);},style:{marginBlockEnd:sizing.size_080}}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageAltTextTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image Alt Text"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:imageAltTextTextAreaId,value:imageAltText,placeholder:"Example: Graph of a linear function...",onChange:value=>{setImageAltText(value);}}),jsxRuntimeExports.jsxs("span",{className:styles.buttonRow,children:[onDelete&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:trashIcon$1,style:{alignSelf:"flex-start"},onClick:onDelete,children:"Delete this image"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:imageUrl===initialImageUrl&&imageAltText===initialImageAltText,style:{alignSelf:"flex-start"},onClick:handleSave,children:"Save image"})]})]})}
1691
1702
 
1692
- var styles = {"tile":"perseus_fAVMAcnB","radioOptionActionsContainer":"perseus_qMTuHJ53"};
1703
+ function getMovedChoices(choices,hasNoneOfTheAbove,choiceIndex,movement){const newChoices=[...choices];const[removedChoice]=newChoices.splice(choiceIndex,1);switch(movement){case "top":if(choiceIndex===0){return choices}newChoices.unshift(removedChoice);break;case "up":if(choiceIndex===0){return choices}newChoices.splice(choiceIndex-1,0,removedChoice);break;case "down":if(choiceIndex===choices.length-1){return choices}if(choiceIndex===choices.length-2&&hasNoneOfTheAbove){return choices}newChoices.splice(choiceIndex+1,0,removedChoice);break;case "bottom":if(choiceIndex===choices.length-1){return choices}if(hasNoneOfTheAbove){const removedNoneOfTheAbove=newChoices.pop();newChoices.push(removedChoice);if(removedNoneOfTheAbove){newChoices.push(removedNoneOfTheAbove);}}else {newChoices.push(removedChoice);}break}return newChoices}function setImageProxyFromMarkdownContent(markdownContent){const images=[];const parsedMarkdown=PerseusMarkdown.parse(markdownContent,{});PerseusMarkdown.traverseContent(parsedMarkdown,node=>{if(node.type==="image"){images.push({url:node.target||"",altText:node.alt||""});}});let proxiedContent=markdownContent;images.forEach((image,index)=>{const originalPattern=`![${image.altText}](${image.url})`;const replacement=`![Image ${index+1}]`;const patternIndex=proxiedContent.indexOf(originalPattern);if(patternIndex!==-1){proxiedContent=proxiedContent.substring(0,patternIndex)+replacement+proxiedContent.substring(patternIndex+originalPattern.length);}});return [proxiedContent,images]}function setMarkdownContentFromImageProxy(proxiedContent,images){let markdownContent=proxiedContent;for(let i=0;i<images.length;i++){const image=images[i];markdownContent=markdownContent.replace(`![Image ${i+1}]`,`![${image.altText}](${image.url})`);}return markdownContent}
1704
+
1705
+ const RadioOptionContentAndImageEditor=props=>{const{content,choiceIndex,onContentChange,isNoneOfTheAbove}=props;const uniqueId=React.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const[proxiedContent,setProxiedContent]=React.useState("");const[images,setImages]=React.useState([]);const[addingImage,setAddingImage]=React.useState(false);React.useEffect(()=>{const[proxiedContent,images]=setImageProxyFromMarkdownContent(content??"");setProxiedContent(proxiedContent);setImages(images);},[content]);const handleAddImage=(choiceIndex,imageUrl,imageAltText)=>{const newContent=`${content}
1706
+ ![${imageAltText}](${imageUrl})`;onContentChange(choiceIndex,newContent);};const handleDeleteImage=imageIndex=>{const substr=`![Image ${imageIndex+1}]`;const newProxiedContent=proxiedContent.replace(substr,"");setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handleUpdateImage=(imageIndex,url,altText)=>{const newImages=[...images];newImages[imageIndex]={url,altText};setImages(newImages);const newContent=setMarkdownContentFromImageProxy(proxiedContent,newImages);onContentChange(choiceIndex,newContent);};const handleContentChange=(choiceIndex,newProxiedContent)=>{setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handlePaste=e=>{const imageURL=e.clipboardData.getData("text");if(imageURL.includes("cdn.kastatic.org")||imageURL.includes("graphie")){e.preventDefault();handleAddImage(choiceIndex,imageURL,"");}};const handleDeleteImageConfirmation=imageIndex=>{if(window.confirm("Are you sure you want to delete this image?")){handleDeleteImage(imageIndex);}};if(isNoneOfTheAbove){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:contentTextAreaId,value:"None of the above",disabled:true,onChange:()=>{}})]})}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Content"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:contentTextAreaId,value:proxiedContent,placeholder:"Type a choice here...",onChange:value=>{handleContentChange(choiceIndex,value);},onPaste:handlePaste}),!addingImage&&jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,size:"small",kind:"tertiary",style:{alignSelf:"flex-start"},onClick:()=>{setAddingImage(true);},children:"Add image"}),addingImage&&jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:"",initialImageAltText:"",containerClassName:styles.imageEditorContainer,onSave:(imageUrl,imageAltText)=>{handleAddImage(choiceIndex,imageUrl,imageAltText);},onClose:()=>{setAddingImage(false);}}),images?.map((image,imageIndex)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:`Image ${imageIndex+1}`,expanded:true,containerStyle:{backgroundColor:semanticColor.surface.primary,marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},panelStyle:{paddingBlockEnd:sizing.size_120},children:[jsxRuntimeExports.jsx("img",{src:image.url,alt:image.altText,style:{marginBlockEnd:sizing.size_080}}),jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:image.url,initialImageAltText:image.altText,onSave:(imageUrl,imageAltText)=>{handleUpdateImage(imageIndex,imageUrl,imageAltText);},onDelete:()=>{handleDeleteImageConfirmation(imageIndex);}})]},image.url))??null]})};
1693
1707
 
1694
1708
  function RadioOptionSettingsActions({content,showDelete,showMove,onDelete,onMove}){return jsxRuntimeExports.jsxs("div",{className:styles.radioOptionActionsContainer,children:[showDelete&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:trashIcon$1,onClick:()=>{if(window.confirm(`Are you sure you want to remove this choice?
1695
1709
 
@@ -1697,11 +1711,9 @@ ${content}`)){onDelete();}},children:"Remove"}),showMove&&jsxRuntimeExports.jsxs
1697
1711
 
1698
1712
  function RadioStatusPill({index,correct,multipleSelect,onClick}){return jsxRuntimeExports.jsx(Pill,{size:"large",style:{marginInlineEnd:sizing.size_080,color:correct?color.white:color.red,backgroundColor:correct?color.activeGreen:color.fadedRed8,borderRadius:multipleSelect?border.radius.radius_040:sizing.size_240,border:`1px solid ${correct?color.activeGreen:color.red}`,width:sizing.size_560,flexDirection:"row"},onClick:onClick,children:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(PhosphorIcon,{size:"small",icon:correct?checkIcon:minusCircleIcon,style:{marginInlineEnd:sizing.size_060},color:correct?color.white:color.red}),String.fromCharCode(65+index)]})})}
1699
1713
 
1700
- function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove}){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(HeadingXSmall,{style:{display:"inline",marginInlineEnd:sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:sizing.size_080,outlineColor:correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:sizing.size_080,outlineColor:!correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:contentTextAreaId,value:isNoneOfTheAbove?"None of the above":content,disabled:isNoneOfTheAbove,placeholder:"Type a choice here...",onChange:value=>{onContentChange(index,value);},style:{marginBlockEnd:sizing.size_080}}),jsxRuntimeExports.jsxs(HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,children:["Rationale",jsxRuntimeExports.jsx(AutoResizingTextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);}})]}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})}
1701
-
1702
- function getMovedChoices(choices,hasNoneOfTheAbove,choiceIndex,movement){const newChoices=[...choices];const[removedChoice]=newChoices.splice(choiceIndex,1);switch(movement){case "top":if(choiceIndex===0){return choices}newChoices.unshift(removedChoice);break;case "up":if(choiceIndex===0){return choices}newChoices.splice(choiceIndex-1,0,removedChoice);break;case "down":if(choiceIndex===choices.length-1){return choices}if(choiceIndex===choices.length-2&&hasNoneOfTheAbove){return choices}newChoices.splice(choiceIndex+1,0,removedChoice);break;case "bottom":if(choiceIndex===choices.length-1){return choices}if(hasNoneOfTheAbove){const removedNoneOfTheAbove=newChoices.pop();newChoices.push(removedChoice);if(removedNoneOfTheAbove){newChoices.push(removedNoneOfTheAbove);}}else {newChoices.push(removedChoice);}break}return newChoices}
1714
+ function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove}){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(HeadingXSmall,{style:{display:"inline",marginInlineEnd:sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:sizing.size_080,outlineColor:correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:sizing.size_080,outlineColor:!correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);}}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})}
1703
1715
 
1704
- class RadioEditor extends React.Component{serialize(){const{choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled}=this.props;return {choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled,numCorrect:deriveNumCorrect(choices)}}render(){const numCorrect=deriveNumCorrect(this.props.choices);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link$1,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Specify number correct",checked:this.props.countChoices,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(Footnote,{children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{index:index,choice:choice,multipleSelect:this.props.multipleSelect,onStatusChange:this.onStatusChange,onContentChange:this.onContentChange,onRationaleChange:this.onRationaleChange,showDelete:this.props.choices.length>=2,showMove:this.props.choices.length>1&&!choice.isNoneOfTheAbove,onDelete:()=>this.onDelete(index),onMove:this.handleMove},`choice-${index}}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),children:"None of the above"})]})]})}constructor(...args){super(...args),this.onMultipleSelectChange=allowMultiple=>{const isMultipleSelect=allowMultiple.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:deriveNumCorrect(choices)});},this.onCountChoicesChange=count=>{const countChoices=count.countChoices;this.props.onChange({countChoices});},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content}});this.props.onChange({choices,numCorrect:deriveNumCorrect(choices)});},this.onStatusChange=(choiceIndex,correct)=>{let newCheckedList;if(correct&&!this.props.multipleSelect){newCheckedList=this.props.choices.map(_=>false);}else {newCheckedList=this.props.choices.map(c=>c.correct);}newCheckedList[choiceIndex]=correct;this.onChange({checked:newCheckedList});},this.onContentChange=(choiceIndex,newContent)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],content:newContent};this.props.onChange({choices:choices});},this.onRationaleChange=(choiceIndex,newRationale)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],rationale:newRationale};if(newRationale===""){delete choices[choiceIndex].rationale;}this.props.onChange({choices:choices});},this.onDelete=choiceIndex=>{const choices=this.props.choices.slice();const deleted=choices[choiceIndex];choices.splice(choiceIndex,1);this.props.onChange({choices,hasNoneOfTheAbove:this.props.hasNoneOfTheAbove&&!deleted.isNoneOfTheAbove,numCorrect:deriveNumCorrect(choices)});},this.addChoice=(noneOfTheAbove,e)=>{e.preventDefault();const choices=this.props.choices.slice();const newChoice={isNoneOfTheAbove:noneOfTheAbove,content:""};const addIndex=choices.length-(this.props.hasNoneOfTheAbove?1:0);choices.splice(addIndex,0,newChoice);this.props.onChange({choices:choices,hasNoneOfTheAbove:noneOfTheAbove||this.props.hasNoneOfTheAbove},()=>{this.refs[`choice-editor${addIndex}`].refs["content-editor"].focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{this.refs["choice-editor0"].refs["content-editor"].focus();return true},this.getSaveWarnings=()=>{if(!_.some(_.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1716
+ class RadioEditor extends React.Component{serialize(){const{choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled}=this.props;return {choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled,numCorrect:deriveNumCorrect(choices)}}render(){const numCorrect=deriveNumCorrect(this.props.choices);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link$1,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Specify number correct",checked:this.props.countChoices,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(Footnote,{children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{index:index,choice:choice,multipleSelect:this.props.multipleSelect,onStatusChange:this.onStatusChange,onContentChange:this.onContentChange,onRationaleChange:this.onRationaleChange,showDelete:this.props.choices.length>=2,showMove:this.props.choices.length>1&&!choice.isNoneOfTheAbove,onDelete:()=>this.onDelete(index),onMove:this.handleMove},`choice-${index}}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),children:"None of the above"})]})]})}constructor(...args){super(...args),this.onMultipleSelectChange=allowMultiple=>{const isMultipleSelect=allowMultiple.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:deriveNumCorrect(choices)});},this.onCountChoicesChange=count=>{const countChoices=count.countChoices;this.props.onChange({countChoices});},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content}});this.props.onChange({choices,numCorrect:deriveNumCorrect(choices)});},this.onStatusChange=(choiceIndex,correct)=>{let newCheckedList;if(correct&&!this.props.multipleSelect){newCheckedList=this.props.choices.map(_=>false);}else {newCheckedList=this.props.choices.map(c=>c.correct);}newCheckedList[choiceIndex]=correct;this.onChange({checked:newCheckedList});},this.onContentChange=(choiceIndex,newContent)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],content:newContent};this.props.onChange({choices:choices});},this.onRationaleChange=(choiceIndex,newRationale)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],rationale:newRationale};if(newRationale===""){delete choices[choiceIndex].rationale;}this.props.onChange({choices:choices});},this.onDelete=choiceIndex=>{const choices=this.props.choices.slice();const deleted=choices[choiceIndex];choices.splice(choiceIndex,1);this.props.onChange({choices,hasNoneOfTheAbove:this.props.hasNoneOfTheAbove&&!deleted.isNoneOfTheAbove,numCorrect:deriveNumCorrect(choices)});},this.addChoice=(noneOfTheAbove,e)=>{e.preventDefault();const choices=this.props.choices.slice();const newChoice={isNoneOfTheAbove:noneOfTheAbove,content:"",id:crypto.randomUUID()};const addIndex=choices.length-(this.props.hasNoneOfTheAbove?1:0);choices.splice(addIndex,0,newChoice);this.props.onChange({choices:choices,hasNoneOfTheAbove:noneOfTheAbove||this.props.hasNoneOfTheAbove},()=>{this.refs[`choice-editor${addIndex}`].refs["content-editor"].focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{this.refs["choice-editor0"].refs["content-editor"].focus();return true},this.getSaveWarnings=()=>{if(!_.some(_.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1705
1717
 
1706
1718
  const{InfoTip: InfoTip$2,TextListEditor}=components;const HORIZONTAL="horizontal";const VERTICAL="vertical";class SorterEditor extends React.Component{render(){const editor=this;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answer (in the correct order) here. The preview on the right will have the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correct,onChange:function(options,cb){editor.props.onChange({correct:options},cb);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text and larger images."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.serialize=()=>{return _.pick(this.props,"correct","layout","padding")};}}SorterEditor.propTypes={correct:PropTypes.array,layout:PropTypes.oneOf([HORIZONTAL,VERTICAL]),padding:PropTypes.bool};SorterEditor.widgetName="sorter";SorterEditor.defaultProps=sorterLogic.defaultWidgetOptions;
1707
1719