@khanacademy/perseus-editor 38.1.2 → 39.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/all-editors.d.ts +49 -9
  2. package/dist/article-editor.d.ts +2 -1
  3. package/dist/components/widget-editor.d.ts +1 -1
  4. package/dist/es/index.js +35 -35
  5. package/dist/es/index.js.map +1 -1
  6. package/dist/{item-extras-editor.d.ts → extras-editor.d.ts} +2 -2
  7. package/dist/index.js +35 -35
  8. package/dist/index.js.map +1 -1
  9. package/dist/item-editor.d.ts +3 -3
  10. package/dist/testing/feature-flags-util.d.ts +1 -0
  11. package/dist/widgets/categorizer-editor/categorizer-editor.d.ts +0 -1
  12. package/dist/widgets/cs-program-editor/cs-program-editor.d.ts +0 -1
  13. package/dist/widgets/definition-editor/definition-editor.d.ts +0 -1
  14. package/dist/widgets/deprecated-standin-editor/deprecated-standin-editor.d.ts +0 -1
  15. package/dist/widgets/dropdown-editor/dropdown-editor.d.ts +0 -1
  16. package/dist/widgets/explanation-editor/explanation-editor.d.ts +0 -1
  17. package/dist/widgets/expression-editor/expression-editor.d.ts +0 -1
  18. package/dist/widgets/free-response-editor/free-response-editor.d.ts +0 -1
  19. package/dist/widgets/graded-group-editor/graded-group-editor.d.ts +0 -1
  20. package/dist/widgets/graded-group-set-editor/graded-group-set-editor.d.ts +0 -1
  21. package/dist/widgets/grapher-editor/grapher-editor.d.ts +0 -1
  22. package/dist/widgets/group-editor/group-editor.d.ts +0 -1
  23. package/dist/widgets/iframe-editor/iframe-editor.d.ts +0 -1
  24. package/dist/widgets/image-editor/image-editor.d.ts +0 -1
  25. package/dist/widgets/input-number-editor/input-number-editor.d.ts +0 -1
  26. package/dist/widgets/interaction-editor/interaction-editor.d.ts +0 -1
  27. package/dist/widgets/interactive-graph-editor/interactive-graph-editor.d.ts +52 -29
  28. package/dist/widgets/label-image-editor/label-image-editor.d.ts +0 -1
  29. package/dist/widgets/matcher-editor/matcher-editor.d.ts +0 -1
  30. package/dist/widgets/matrix-editor/matrix-editor.d.ts +0 -1
  31. package/dist/widgets/measurer-editor/measurer-editor.d.ts +0 -1
  32. package/dist/widgets/number-line-editor/number-line-editor.d.ts +0 -1
  33. package/dist/widgets/numeric-input-editor/numeric-input-editor.d.ts +0 -1
  34. package/dist/widgets/orderer-editor/orderer-editor.d.ts +0 -1
  35. package/dist/widgets/phet-simulation-editor/phet-simulation-editor.d.ts +0 -1
  36. package/dist/widgets/plotter-editor/plotter-editor.d.ts +0 -1
  37. package/dist/widgets/python-program-editor/python-program-editor.d.ts +0 -1
  38. package/dist/widgets/radio-editor/radio-editor.d.ts +0 -1
  39. package/dist/widgets/sorter-editor/sorter-editor.d.ts +0 -1
  40. package/dist/widgets/table-editor/table-editor.d.ts +0 -1
  41. package/dist/widgets/video-editor/video-editor.d.ts +0 -1
  42. package/package.json +9 -9
package/dist/es/index.js CHANGED
@@ -66,7 +66,7 @@ import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
66
66
  import arrowDown from '@phosphor-icons/core/regular/arrow-down.svg';
67
67
  import arrowUp from '@phosphor-icons/core/regular/arrow-up.svg';
68
68
 
69
- const libName="@khanacademy/perseus-editor";const libVersion="38.1.2";addLibraryVersionToPerseusDebug(libName,libVersion);
69
+ const libName="@khanacademy/perseus-editor";const libVersion="39.0.0";addLibraryVersionToPerseusDebug(libName,libVersion);
70
70
 
71
71
  var jsxRuntime = {exports: {}};
72
72
 
@@ -1516,11 +1516,11 @@ class ItemDiff extends React.Component{render(){const{before,after}=this.props;c
1516
1516
 
1517
1517
  class HintEditor extends React.Component{serialize(){invariant(this.editor.current,"cannot serialize HintEditor with no Editor");return {...this.editor.current.serialize(),replace:this.props.replace??undefined}}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,placeholder:"Type your hint here...",imageUploader:this.props.imageUploader,onChange:this.props.onChange,widgetIsOpen:this.props.widgetIsOpen},this.props.itemId),this.props.isLast&&jsxRuntimeExports.jsx(BodyText,{size:"xsmall",children:"The last hint is automatically bolded."}),jsxRuntimeExports.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[this.props.showMoveButtons&&jsxRuntimeExports.jsxs("div",{className:"reorder-hints",children:[jsxRuntimeExports.jsx(IconButton,{icon:arrowCircleDownIcon,size:"small",kind:"tertiary",onClick:_.partial(this.props.onMove,1),disabled:this.props.isLast}),jsxRuntimeExports.jsx(IconButton,{icon:arrowCircleUpIcon,size:"small",kind:"tertiary",onClick:_.partial(this.props.onMove,-1),disabled:this.props.isFirst})]}),jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.replace,onChange:newCheckedState=>{this.props.onChange({replace:newCheckedState});},label:"Replace previous hint",style:{display:"inline-block"}})]}),this.props.showRemoveButton&&jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,size:"small",kind:"tertiary",disabled:this.props.apiOptions?.editingDisabled,onClick:this.props.onRemove,style:{marginInlineStart:"auto",display:"flex"},children:"Remove this hint"})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.handleReplaceChanged=e=>{this.props.onChange({replace:e.target.checked});},this.focus=()=>{this.editor.current?.focus();},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()};}}HintEditor.defaultProps={className:"",content:"",replace:false,showMoveButtons:true,showTitle:true,showRemoveButton:true};class CombinedHintEditor extends React.Component{serialize(){invariant(this.editor.current,"cannot serialize CombinedHintEditor with no HintEditor");return this.editor.current.serialize()}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(PreviewWithIframe,{isMobile:isMobile,seamless:true,url:this.props.previewURL,content:{type:"hint",data:{hint:this.props.hint,pos:this.props.pos,apiOptions:this.props.apiOptions||ApiOptions.defaults,linterContext:{contentType:"hint",highlightLint:this.props.highlightLint}}}})})})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.focus=()=>{this.editor.current?.focus();};}}class CombinedHintsEditor extends React.Component{handleHintChange(i,newProps){const hints=[...this.props.hints];hints[i]=_.extend({},this.serializeHint(i),newProps);this.props.onChange({hints:hints});}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});}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});}serialize(){return this.props.hints.map((_,i)=>this.serializeHint(i))}serializeHint(index){return this.refs["hintEditor"+index].serialize()}render(){const{itemId,hints}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const hintElems=hints.map((hint,i)=>{return jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children: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,widgetIsOpen:this.props.widgetIsOpen})},"hintEditor"+i)});return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[hintElems,jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,disabled:editingDisabled,size:"small",onClick:this.addHint,children:"Add a hint"})})]})}constructor(...args){super(...args),this.addHint=()=>{const hint={content:"",images:{},widgets:{}};const hints=[...this.props.hints,hint];this.props.onChange({hints:hints});},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()};}}CombinedHintsEditor.HintEditor=HintEditor;CombinedHintsEditor.defaultProps={hints:[],onChange:()=>{}};
1518
1518
 
1519
- const calculatorVariants=[{label:"Scientific calculator",variant:"scientific"},{label:"Graphing calculator",variant:"graphing"},{label:"Four-function calculator",variant:"four_function"}];class ItemExtrasEditor extends React.Component{shouldShowCalculatorVariants(){return this.props.calculatorVariant!==undefined}shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}serialize(){const data={...ItemExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}data.calculatorVariant=this.props.calculatorVariant;return data}render(){const{editingDisabled,calculatorVariant}=this.props;return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",disabled:editingDisabled,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.shouldShowCalculatorVariants(),onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState,calculatorVariant:newCheckedState?"scientific":undefined});}}),isFeatureOn(this.props,"desmos-calculator")&&calculatorVariant!==undefined&&jsxRuntimeExports.jsx(RadioGroup,{groupName:"calculator-variant",selectedValue:calculatorVariant,onChange:this.handleVariantChange,style:styles$R.indented,children:calculatorVariants.map((calcVariant,_)=>jsxRuntimeExports.jsx(Choice,{value:calcVariant.variant,label:calcVariant.label,disabled:editingDisabled,style:styles$R.calculatorChoice},calcVariant.variant))}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show financial calculator",disabled:editingDisabled,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",disabled:editingDisabled,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",disabled:editingDisabled,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",disabled:editingDisabled,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",disabled:editingDisabled,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",disabled:editingDisabled,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.handleVariantChange=newVariant=>{const selected=calculatorVariants.find(({variant})=>variant===newVariant);if(selected){this.props.onChange({calculatorVariant:selected.variant});}};}}ItemExtrasEditor.defaultProps=getDefaultAnswerArea();const ItemExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$R.checkbox,props.indent?styles$R.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{disabled:props.disabled,label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$R=StyleSheet.create({indented:{marginInlineStart:spacing.large_24},calculatorChoice:{marginBlock:sizing.size_010}});
1519
+ const calculatorVariants=[{label:"Scientific calculator",variant:"scientific"},{label:"Graphing calculator",variant:"graphing"},{label:"Four-function calculator",variant:"four_function"}];class ExtrasEditor extends React.Component{shouldShowCalculatorVariants(){return this.props.calculatorVariant!==undefined}shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}serialize(){const data={...ExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}data.calculatorVariant=this.props.calculatorVariant;return data}render(){const{editingDisabled,calculatorVariant}=this.props;return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ExtraCheckbox,{label:"Show calculator",disabled:editingDisabled,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.shouldShowCalculatorVariants(),onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState,calculatorVariant:newCheckedState?"scientific":undefined});}}),isFeatureOn(this.props,"desmos-calculator")&&calculatorVariant!==undefined&&jsxRuntimeExports.jsx(RadioGroup,{groupName:"calculator-variant",selectedValue:calculatorVariant,onChange:this.handleVariantChange,style:styles$R.indented,children:calculatorVariants.map((calcVariant,_)=>jsxRuntimeExports.jsx(Choice,{value:calcVariant.variant,label:calcVariant.label,disabled:editingDisabled,style:styles$R.calculatorChoice},calcVariant.variant))}),jsxRuntimeExports.jsx(ExtraCheckbox,{label:"Show financial calculator",disabled:editingDisabled,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(ExtraCheckbox,{label:"Include monthly payment",disabled:editingDisabled,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(ExtraCheckbox,{label:"Include total amount",disabled:editingDisabled,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(ExtraCheckbox,{label:"Include time-to-pay-off",disabled:editingDisabled,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(ExtraCheckbox,{label:"Show periodic table",disabled:editingDisabled,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(ExtraCheckbox,{label:"Include key/legend with periodic table",disabled:editingDisabled,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.handleVariantChange=newVariant=>{const selected=calculatorVariants.find(({variant})=>variant===newVariant);if(selected){this.props.onChange({calculatorVariant:selected.variant});}};}}ExtrasEditor.defaultProps=getDefaultAnswerArea();const ExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$R.checkbox,props.indent?styles$R.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{disabled:props.disabled,label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$R=StyleSheet.create({indented:{marginInlineStart:spacing.large_24},calculatorChoice:{marginBlock:sizing.size_010}});
1520
1520
 
1521
1521
  function legacyPerseusLintEqual(a,b){return a.length===b.length&&a.every((warning,i)=>warning===b[i])}function inputsEqual(a,b){return a.question===b.question&&a.apiOptions===b.apiOptions&&a.deviceType===b.deviceType&&a.highlightLint===b.highlightLint&&a.problemNum===b.problemNum&&legacyPerseusLintEqual(a.legacyPerseusLint,b.legacyPerseusLint)}function buildContent(inputs){return {type:"question",data:{question:inputs.question,apiOptions:{...ApiOptions.defaults,...inputs.apiOptions,customKeypad:inputs.deviceType==="phone"||inputs.deviceType==="tablet"},linterContext:{contentType:"exercise",highlightLint:inputs.highlightLint},reviewMode:true,legacyPerseusLint:inputs.legacyPerseusLint,problemNum:inputs.problemNum}}}function createPreviewContentDeriver(){let lastInputs=null;let lastContent=null;return inputs=>{if(!inputs.question){return null}if(lastInputs&&inputsEqual(inputs,lastInputs)){return lastContent}const content=buildContent(inputs);lastInputs=inputs;lastContent=content;return content}}
1522
1522
 
1523
- class ItemEditor extends React.Component{serialize(){invariant(this.questionEditor.current,"cannot serialize ItemEditor without Editor");invariant(this.itemExtrasEditor.current,"cannot serialize ItemEditor without ItemExtrasEditor");invariant(this.hintsEditor.current,"cannot serialize ItemEditor without CombinedHintsEditor");return {question:this.questionEditor.current.serialize(),answerArea:this.itemExtrasEditor.current.serialize(),hints:this.hintsEditor.current.serialize()}}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";const editingDisabled=this.props.apiOptions?.editingDisabled??false;const a11yScanningEnabled=this.context?.a11yScanningEnabled??false;const highlightInstanceIds=this.context?.highlightInstanceIds??[];return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-question-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question"}),jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(Editor,{ref:this.questionEditor,placeholder:"Type your question here...",className:"perseus-question-editor",imageUploader:this.props.imageUploader,onChange:this.handleEditorChange,apiOptions:this.props.apiOptions,showWordCount:true,widgetIsOpen:this.props.widgetIsOpen,additionalTemplates:this.props.additionalTemplates,...this.props.question},this.props.itemId)})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx("div",{id:"problemarea",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(PreviewWithIframe,{isMobile:isMobile,seamless:true,url:this.props.previewURL,content:this.derivePreviewContent({question:this.props.question,apiOptions:this.props.apiOptions,deviceType:this.props.deviceType,highlightLint:this.props.highlightLint,problemNum:this.props.problemNum,legacyPerseusLint:this.getSaveWarnings()??[]}),a11yScanningEnabled:a11yScanningEnabled,highlightInstanceIds:highlightInstanceIds,onA11yReport:this.handleA11yReport},this.props.deviceType)})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-answer-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question extras"}),jsxRuntimeExports.jsx(ItemExtrasEditor,{ref:this.itemExtrasEditor,apiOptions:this.props.apiOptions,onChange:this.handleItemExtrasChange,editingDisabled:editingDisabled,...this.props.answerArea})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell"})]}),jsxRuntimeExports.jsx(CombinedHintsEditor,{ref:this.hintsEditor,itemId:this.props.itemId,hints:this.props.hints,imageUploader:this.props.imageUploader,onChange:this.props.onChange,deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,previewURL:this.props.previewURL,highlightLint:this.props.highlightLint,widgetIsOpen:this.props.widgetIsOpen})]})}constructor(...args){super(...args),this.questionEditor=React.createRef(),this.itemExtrasEditor=React.createRef(),this.hintsEditor=React.createRef(),this.derivePreviewContent=createPreviewContentDeriver(),this.updateProps=newProps=>{const props=_(this.props).pick("question","answerArea");this.props.onChange(_(props).extend(newProps));},this.handleEditorChange=newProps=>{const question=_.extend({},this.props.question,newProps);this.updateProps({question});},this.handleItemExtrasChange=newProps=>{const answerArea=_.extend({},this.props.answerArea,newProps);this.updateProps({answerArea});},this.getSaveWarnings=()=>{return [...this.questionEditor.current?.getSaveWarnings()??[],...this.hintsEditor.current?.getSaveWarnings()??[]]},this.handleA11yReport=report=>{this.context?.onA11yReport(report);};}}ItemEditor.contextType=A11yContext;ItemEditor.defaultProps={onChange:()=>{},question:{},answerArea:{}};
1523
+ class ItemEditor extends React.Component{serialize(){invariant(this.questionEditor.current,"cannot serialize ItemEditor without Editor");invariant(this.extrasEditor.current,"cannot serialize ItemEditor without ExtrasEditor");invariant(this.hintsEditor.current,"cannot serialize ItemEditor without CombinedHintsEditor");return {question:this.questionEditor.current.serialize(),answerArea:this.extrasEditor.current.serialize(),hints:this.hintsEditor.current.serialize()}}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";const editingDisabled=this.props.apiOptions?.editingDisabled??false;const a11yScanningEnabled=this.context?.a11yScanningEnabled??false;const highlightInstanceIds=this.context?.highlightInstanceIds??[];return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-question-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question"}),jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(Editor,{ref:this.questionEditor,placeholder:"Type your question here...",className:"perseus-question-editor",imageUploader:this.props.imageUploader,onChange:this.handleEditorChange,apiOptions:this.props.apiOptions,showWordCount:true,widgetIsOpen:this.props.widgetIsOpen,additionalTemplates:this.props.additionalTemplates,...this.props.question},this.props.itemId)})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx("div",{id:"problemarea",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(PreviewWithIframe,{isMobile:isMobile,seamless:true,url:this.props.previewURL,content:this.derivePreviewContent({question:this.props.question,apiOptions:this.props.apiOptions,deviceType:this.props.deviceType,highlightLint:this.props.highlightLint,problemNum:this.props.problemNum,legacyPerseusLint:this.getSaveWarnings()??[]}),a11yScanningEnabled:a11yScanningEnabled,highlightInstanceIds:highlightInstanceIds,onA11yReport:this.handleA11yReport},this.props.deviceType)})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-answer-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question extras"}),jsxRuntimeExports.jsx(ExtrasEditor,{ref:this.extrasEditor,apiOptions:this.props.apiOptions,onChange:this.handleExtrasChange,editingDisabled:editingDisabled,...this.props.answerArea})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell"})]}),jsxRuntimeExports.jsx(CombinedHintsEditor,{ref:this.hintsEditor,itemId:this.props.itemId,hints:this.props.hints,imageUploader:this.props.imageUploader,onChange:this.props.onChange,deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,previewURL:this.props.previewURL,highlightLint:this.props.highlightLint,widgetIsOpen:this.props.widgetIsOpen})]})}constructor(...args){super(...args),this.questionEditor=React.createRef(),this.extrasEditor=React.createRef(),this.hintsEditor=React.createRef(),this.derivePreviewContent=createPreviewContentDeriver(),this.updateProps=newProps=>{const props=_(this.props).pick("question","answerArea");this.props.onChange(_(props).extend(newProps));},this.handleEditorChange=newProps=>{const question=_.extend({},this.props.question,newProps);this.updateProps({question});},this.handleExtrasChange=newProps=>{const answerArea=_.extend({},this.props.answerArea,newProps);this.updateProps({answerArea});},this.getSaveWarnings=()=>{return [...this.questionEditor.current?.getSaveWarnings()??[],...this.hintsEditor.current?.getSaveWarnings()??[]]},this.handleA11yReport=report=>{this.context?.onA11yReport(report);};}}ItemEditor.contextType=A11yContext;ItemEditor.defaultProps={onChange:()=>{},question:{},answerArea:{}};
1524
1524
 
1525
1525
  function buildDeviceApiOptions(inputs){return {...ApiOptions.defaults,...inputs.apiOptions,customKeypad:inputs.touch,isMobile:inputs.touch}}function createDeviceApiOptionsDeriver(){let lastInputs=null;let lastResult=null;return inputs=>{if(lastResult!=null&&lastInputs!=null&&lastInputs.apiOptions===inputs.apiOptions&&lastInputs.touch===inputs.touch){return lastResult}const result=buildDeviceApiOptions(inputs);lastInputs=inputs;lastResult=result;return result}}
1526
1526
 
@@ -1546,40 +1546,40 @@ const USAGE="Usage:\n"+" this.change({propName: 5}, callback);\n"+' this.chang
1546
1546
 
1547
1547
  const EditorJsonify={serialize:function(){return excludeDenylistKeys(this.props)}};
1548
1548
 
1549
- const Categorizer=Categorizer$1.widget;class CategorizerEditor extends React.Component{render(){const categorizerProps={options:{items:this.props.items,categories:this.props.categories,randomizeItems:false,values:[]},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,{options:this.props.categories,onChange:cat=>{this.change("categories",cat);},layout:"horizontal"}),"Items:",jsxRuntimeExports.jsx(TextListEditor,{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 deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CategorizerEditor.widgetName="categorizer";CategorizerEditor.defaultProps=categorizerLogic.defaultWidgetOptions;
1549
+ const Categorizer=Categorizer$1.widget;class CategorizerEditor extends React.Component{render(){const categorizerProps={options:{items:this.props.items,categories:this.props.categories,randomizeItems:false,values:[]},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,{options:this.props.categories,onChange:cat=>{this.change("categories",cat);},layout:"horizontal"}),"Items:",jsxRuntimeExports.jsx(TextListEditor,{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 deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CategorizerEditor.defaultProps=categorizerLogic.defaultWidgetOptions;
1550
1550
 
1551
1551
  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};}}
1552
1552
 
1553
- 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 deprecatedChangeableChange.apply(this,args)};}};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=this.props.pairs.map((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 deprecatedChangeableChange.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);};}};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,{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,{pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip,{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 deprecatedChangeableChange.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}`;const fetchProgramInfo=async()=>{const response=await fetch(baseUrl);if(!response.ok){throw new Error(`Request for scratchpad info failed with status ${response.status} ${response.statusText}`)}return response.json()};fetchProgramInfo().then(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});},error=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CSProgramEditor.widgetName="cs-program";
1553
+ 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 deprecatedChangeableChange.apply(this,args)};}};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=this.props.pairs.map((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 deprecatedChangeableChange.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);};}};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,{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,{pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip,{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 deprecatedChangeableChange.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}`;const fetchProgramInfo=async()=>{const response=await fetch(baseUrl);if(!response.ok){throw new Error(`Request for scratchpad info failed with status ${response.status} ${response.statusText}`)}return response.json()};fetchProgramInfo().then(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});},error=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}
1554
1554
 
1555
- const{TextInput: TextInput$5}=components;class DefinitionEditor extends React.Component{static initializeWidgetOptions(params){const defaultWidgetOptions={...definitionLogic.defaultWidgetOptions};if(params.selectedText){defaultWidgetOptions.togglePrompt=params.selectedText;}return defaultWidgetOptions}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$5,{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 deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DefinitionEditor.widgetName="definition";DefinitionEditor.defaultProps=definitionLogic.defaultWidgetOptions;
1555
+ const{TextInput: TextInput$5}=components;class DefinitionEditor extends React.Component{static initializeWidgetOptions(params){const defaultWidgetOptions={...definitionLogic.defaultWidgetOptions};if(params.selectedText){defaultWidgetOptions.togglePrompt=params.selectedText;}return defaultWidgetOptions}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$5,{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 deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DefinitionEditor.defaultProps=definitionLogic.defaultWidgetOptions;
1556
1556
 
1557
- 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";
1557
+ 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."})]})}}
1558
1558
 
1559
- class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{tag:"label",children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{tag:"label",children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map((choice,i)=>{const choiceBackgroundColor=choice.correct?semanticColor.core.background.success.subtle:semanticColor.core.background.critical.subtle;return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{className:"dropdown-choice",children:[jsxRuntimeExports.jsx("input",{type:"radio",ref:"radio"+i,name:dropdownGroupName,checked:choice.correct,onChange:()=>this.onCorrectChange(i)}),jsxRuntimeExports.jsx(TextField,{value:choice.content,ref:"editor"+i,"aria-label":`Choice ${i+1} content`,disabled:editingDisabled,style:{backgroundColor:choiceBackgroundColor},onChange:newContent=>this.onContentChange(i,newContent)}),jsxRuntimeExports.jsx(IconButton,{icon:trashIcon,"aria-label":"Delete choice",disabled:editingDisabled,kind:"tertiary",size:"small",onClick:()=>this.removeChoice(i)})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:editingDisabled,onClick:this.addChoice,startIcon:plusIcon,children:"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=this.props.choices.map(function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,newContent)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=newContent;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=()=>{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=>{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;
1559
+ class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{tag:"label",children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{tag:"label",children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip,{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(BodyText,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map((choice,i)=>{const choiceBackgroundColor=choice.correct?semanticColor.core.background.success.subtle:semanticColor.core.background.critical.subtle;return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{className:"dropdown-choice",children:[jsxRuntimeExports.jsx("input",{type:"radio",ref:"radio"+i,name:dropdownGroupName,checked:choice.correct,onChange:()=>this.onCorrectChange(i)}),jsxRuntimeExports.jsx(TextField,{value:choice.content,ref:"editor"+i,"aria-label":`Choice ${i+1} content`,disabled:editingDisabled,style:{backgroundColor:choiceBackgroundColor},onChange:newContent=>this.onContentChange(i,newContent)}),jsxRuntimeExports.jsx(IconButton,{icon:trashIcon,"aria-label":"Delete choice",disabled:editingDisabled,kind:"tertiary",size:"small",onClick:()=>this.removeChoice(i)})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:editingDisabled,onClick:this.addChoice,startIcon:plusIcon,children:"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=this.props.choices.map(function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,newContent)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=newContent;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=()=>{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=>{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.defaultProps=dropdownLogic.defaultWidgetOptions;
1560
1560
 
1561
- const{TextInput: TextInput$4}=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$4,{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$4,{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,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.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}ExplanationEditor.widgetName="explanation";ExplanationEditor.defaultProps=explanationLogic.defaultWidgetOptions;
1561
+ const{TextInput: TextInput$4}=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$4,{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$4,{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,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.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}ExplanationEditor.defaultProps=explanationLogic.defaultWidgetOptions;
1562
1562
 
1563
1563
  var styles$P = {"paddedX":"perseus_o-vx07Zg","paddedY":"perseus_873n-udD","answerOption":"perseus_x7ZKrcCV","buttonRow":"perseus_oxdBYi-q","buttonSets":"perseus_086GhAqW","answersSubtitle":"perseus_Xz7kTZ-l","answersGroup":"perseus_xzQO7ISR","answersList":"perseus_AIxq-uWT","deleteButton":"perseus_ppk4h52d"};
1564
1564
 
1565
1565
  const{ButtonGroup: ButtonGroup$7}=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 derivedExtraKeys=deriveExtraKeys({...restProps,answerForms});this.props.onChange({answerForms,extraKeys:derivedExtraKeys});}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 editingDisabled=this.props.apiOptions.editingDisabled??false;const answerOptions=this.props.answerForms.map((ans,index)=>{const expressionProps={options:{times:this.props.times,functions:this.props.functions,buttonSets:this.props.buttonSets,buttonsVisible:"focused",visibleLabel:this.props.visibleLabel,ariaLabel:this.props.ariaLabel,answerForms:this.props.answerForms},userInput:ans.value,handleUserInput:input=>this.changeExpressionWidget(index,input),trackInteraction:()=>{},widgetId:this.props.widgetId+"-"+ans.key};return jsxRuntimeExports.jsx(AnswerOption,{considered:ans.considered,editingDisabled:editingDisabled,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(Heading$1,{size:"medium",children:"Global Options"}),jsxRuntimeExports.jsx("div",{className:styles$P.paddedY,children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Visible label",jsxRuntimeExports.jsx(InfoTip,{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:styles$P.paddedY,children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Aria label",jsxRuntimeExports.jsxs(InfoTip,{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:styles$P.paddedY,children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Function variables",jsxRuntimeExports.jsx(InfoTip,{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:styles$P.paddedY,children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Use × instead of ⋅ for multiplication",jsxRuntimeExports.jsx(InfoTip,{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:styles$P.paddedY,children:[jsxRuntimeExports.jsx(Heading$1,{size:"small",className:styles$P.buttonSets,children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(Heading$1,{size:"medium",children:"Answers"}),jsxRuntimeExports.jsx(BodyText,{size:"small",className:styles$P.answersSubtitle,children:"student responses area matched against these from top to bottom"}),jsxRuntimeExports.jsxs(View,{className:styles$P.answersGroup,children:[jsxRuntimeExports.jsx(View,{className:styles$P.answersList,children:answerOptions}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,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" +
1566
- " 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{editingDisabled}=this.props;const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",className:styles$P.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:styles$P.answerOption,children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,disabled:editingDisabled,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:`${styles$P.paddedY} ${styles$P.paddedX}`,children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip,{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:`${styles$P.paddedY} ${styles$P.paddedX}`,children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip,{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:`${styles$P.buttonRow} ${styles$P.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 wbStyles$1=StyleSheet.create({answerStatusWrong:{backgroundColor:semanticColor.core.background.critical.subtle},answerStatusCorrect:{backgroundColor:semanticColor.core.background.success.subtle},answerStatusUngraded:{backgroundColor:semanticColor.core.background.instructive.subtle}});const consideredButtonStyles={wrong:wbStyles$1.answerStatusWrong,correct:wbStyles$1.answerStatusCorrect,ungraded:wbStyles$1.answerStatusUngraded};
1566
+ " 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.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{editingDisabled}=this.props;const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",disabled:editingDisabled,onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",className:styles$P.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:styles$P.answerOption,children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,disabled:editingDisabled,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:`${styles$P.paddedY} ${styles$P.paddedX}`,children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip,{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:`${styles$P.paddedY} ${styles$P.paddedX}`,children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip,{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:`${styles$P.buttonRow} ${styles$P.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 wbStyles$1=StyleSheet.create({answerStatusWrong:{backgroundColor:semanticColor.core.background.critical.subtle},answerStatusCorrect:{backgroundColor:semanticColor.core.background.success.subtle},answerStatusUngraded:{backgroundColor:semanticColor.core.background.instructive.subtle}});const consideredButtonStyles={wrong:wbStyles$1.answerStatusWrong,correct:wbStyles$1.answerStatusCorrect,ungraded:wbStyles$1.answerStatusUngraded};
1567
1567
 
1568
- class FreeResponseEditor extends React.Component{render(){const editingDisabled=this.props.apiOptions.editingDisabled??false;return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Question",field:jsxRuntimeExports.jsx(TextArea,{value:this.props.question,onChange:newValue=>this.props.onChange({question:newValue})}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:"Placeholder",field:jsxRuntimeExports.jsx(TextArea,{value:this.props.placeholder,onChange:newValue=>this.props.onChange({placeholder:newValue})}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:"Allow unlimited characters",field:jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.allowUnlimitedCharacters,onChange:val=>this.props.onChange({allowUnlimitedCharacters:val})}),styles:{root:styles$O.labeledInputField}}),!this.props.allowUnlimitedCharacters&&jsxRuntimeExports.jsx(LabeledField,{label:"Character limit",field:jsxRuntimeExports.jsx(TextField,{type:"number",min:1,value:String(this.props.characterLimit),onChange:this.handleUpdateCharacterLimit}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs(View,{style:styles$O.criteriaList,tag:"fieldset",children:[jsxRuntimeExports.jsx(BodyText,{tag:"legend",children:"Scoring criteria"}),this.renderCriteriaList(editingDisabled)]}),jsxRuntimeExports.jsx(View,{children:jsxRuntimeExports.jsx(Button,{onClick:this.handleAddCriterion,startIcon:plusCircle,disabled:editingDisabled,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=newValue=>{const val=parseInt(newValue);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=editingDisabled=>{const isDeletable=this.props.scoringCriteria.length>1;return this.props.scoringCriteria.map((criterion,index)=>{return jsxRuntimeExports.jsx(CriterionEditor,{criterion:criterion,index:index,isDeletable:isDeletable,editingDisabled:editingDisabled,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$O.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$O.deleteButtonContainer,children:jsxRuntimeExports.jsx(Button,{"aria-label":`Delete criterion ${props.index+1}`,actionType:"destructive",disabled:!props.isDeletable||props.editingDisabled,kind:"tertiary",onClick:()=>props.onDelete(props.index),size:"small",startIcon:trashIcon$1,children:"Delete"})})]})};const styles$O=StyleSheet.create({criteriaList:{gap:spacing.small_12},criterionContainer:{paddingBlockStart:spacing.xSmall_8,paddingBlockEnd:spacing.xSmall_8,borderBlockEnd:`1px solid ${semanticColor.core.border.neutral.subtle}`,":last-child":{borderBlockEnd:"none"}},deleteButtonContainer:{display:"flex",flexDirection:"row",justifyContent:"flex-end"},labeledInputField:{paddingBlockEnd:spacing.large_24}});
1568
+ class FreeResponseEditor extends React.Component{render(){const editingDisabled=this.props.apiOptions.editingDisabled??false;return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Question",field:jsxRuntimeExports.jsx(TextArea,{value:this.props.question,onChange:newValue=>this.props.onChange({question:newValue})}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:"Placeholder",field:jsxRuntimeExports.jsx(TextArea,{value:this.props.placeholder,onChange:newValue=>this.props.onChange({placeholder:newValue})}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:"Allow unlimited characters",field:jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.allowUnlimitedCharacters,onChange:val=>this.props.onChange({allowUnlimitedCharacters:val})}),styles:{root:styles$O.labeledInputField}}),!this.props.allowUnlimitedCharacters&&jsxRuntimeExports.jsx(LabeledField,{label:"Character limit",field:jsxRuntimeExports.jsx(TextField,{type:"number",min:1,value:String(this.props.characterLimit),onChange:this.handleUpdateCharacterLimit}),styles:{root:styles$O.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs(View,{style:styles$O.criteriaList,tag:"fieldset",children:[jsxRuntimeExports.jsx(BodyText,{tag:"legend",children:"Scoring criteria"}),this.renderCriteriaList(editingDisabled)]}),jsxRuntimeExports.jsx(View,{children:jsxRuntimeExports.jsx(Button,{onClick:this.handleAddCriterion,startIcon:plusCircle,disabled:editingDisabled,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=newValue=>{const val=parseInt(newValue);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=editingDisabled=>{const isDeletable=this.props.scoringCriteria.length>1;return this.props.scoringCriteria.map((criterion,index)=>{return jsxRuntimeExports.jsx(CriterionEditor,{criterion:criterion,index:index,isDeletable:isDeletable,editingDisabled:editingDisabled,onChange:this.handleUpdateCriterion,onDelete:this.handleDeleteCriterion},index)})};}}FreeResponseEditor.defaultProps={...freeResponseLogic.defaultWidgetOptions};const CriterionEditor=function(props){return jsxRuntimeExports.jsxs(View,{style:styles$O.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$O.deleteButtonContainer,children:jsxRuntimeExports.jsx(Button,{"aria-label":`Delete criterion ${props.index+1}`,actionType:"destructive",disabled:!props.isDeletable||props.editingDisabled,kind:"tertiary",onClick:()=>props.onDelete(props.index),size:"small",startIcon:trashIcon$1,children:"Delete"})})]})};const styles$O=StyleSheet.create({criteriaList:{gap:spacing.small_12},criterionContainer:{paddingBlockStart:spacing.xSmall_8,paddingBlockEnd:spacing.xSmall_8,borderBlockEnd:`1px solid ${semanticColor.core.border.neutral.subtle}`,":last-child":{borderBlockEnd:"none"}},deleteButtonContainer:{display:"flex",flexDirection:"row",justifyContent:"flex-end"},labeledInputField:{paddingBlockEnd:spacing.large_24}});
1569
1569
 
1570
1570
  var styles$N = {"title":"perseus_n2P9eL87","input":"perseus_09NCEMrz","hintsTitle":"perseus_fGIysYAE"};
1571
1571
 
1572
- const{TextInput: TextInput$3}=components;class GradedGroupEditor extends React.Component{render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{className:styles$N.title,children:["Title:"," ",jsxRuntimeExports.jsx(TextInput$3,{value:this.props.title,className:styles$N.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,onChange:this.props.onChange,warnNoPrompt:true,warnNoWidgets:true}),!this.props.hint&&jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,size:"small",kind:"tertiary",onClick:this.handleAddHint,disabled:editingDisabled,children:"Add a hint"}),this.props.hint&&jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor",children:[jsxRuntimeExports.jsx("div",{className:styles$N.hintsTitle,children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.hintEditor,content:this.props.hint.content,widgets:this.props.hint.widgets,apiOptions:this.props.apiOptions,images:this.props.hint.images,widgetEnabled:true,onChange:props=>{this.change("hint",Object.assign({},this.props.hint,props));}}),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,size:"small",kind:"tertiary",onClick:this.handleRemoveHint,disabled:editingDisabled,style:{marginInlineStart:"auto",display:"flex"},children:"Remove this hint"})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.hintEditor=React.createRef(),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.handleAddHint=()=>{const hint={content:"",images:{},widgets:{}};this.props.onChange({hint},()=>{this.hintEditor.current?.focus();});},this.handleRemoveHint=()=>{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.widgetName="graded-group";GradedGroupEditor.defaultProps=gradedGroupLogic.defaultWidgetOptions;
1572
+ const{TextInput: TextInput$3}=components;class GradedGroupEditor extends React.Component{render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{className:styles$N.title,children:["Title:"," ",jsxRuntimeExports.jsx(TextInput$3,{value:this.props.title,className:styles$N.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,onChange:this.props.onChange,warnNoPrompt:true,warnNoWidgets:true}),!this.props.hint&&jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,size:"small",kind:"tertiary",onClick:this.handleAddHint,disabled:editingDisabled,children:"Add a hint"}),this.props.hint&&jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor",children:[jsxRuntimeExports.jsx("div",{className:styles$N.hintsTitle,children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.hintEditor,content:this.props.hint.content,widgets:this.props.hint.widgets,apiOptions:this.props.apiOptions,images:this.props.hint.images,widgetEnabled:true,onChange:props=>{this.change("hint",Object.assign({},this.props.hint,props));}}),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,size:"small",kind:"tertiary",onClick:this.handleRemoveHint,disabled:editingDisabled,style:{marginInlineStart:"auto",display:"flex"},children:"Remove this hint"})]}),jsxRuntimeExports.jsx(ExtrasEditor,{...this.props.answerArea??getDefaultAnswerArea(),apiOptions:this.props.apiOptions,editingDisabled:editingDisabled,onChange:changes=>{this.props.onChange({answerArea:{...getDefaultAnswerArea(),...this.props.answerArea,...changes}});}})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.hintEditor=React.createRef(),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.handleAddHint=()=>{const hint={content:"",images:{},widgets:{}};this.props.onChange({hint},()=>{this.hintEditor.current?.focus();});},this.handleRemoveHint=()=>{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(),...this.props.answerArea?{answerArea:this.props.answerArea}:{}}};}}GradedGroupEditor.defaultProps=gradedGroupLogic.defaultWidgetOptions;
1573
1573
 
1574
- class GradedGroupSetEditor extends React.Component{UNSAFE_componentWillMount(){this._editors=[];}render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[this.renderGroups(),jsxRuntimeExports.jsx("button",{onClick:this.addGroup,disabled:editingDisabled,children:"Add group"})]})}constructor(...args){super(...args),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.getSaveWarnings=()=>{return [].concat(...this._editors.map(editor=>editor?editor.getSaveWarnings():[]))},this.serialize=()=>{return {gradedGroups:this.props.gradedGroups}},this.renderGroups=()=>{const gradedGroups=this.props.gradedGroups??[];return gradedGroups.map((group,i)=>jsxRuntimeExports.jsx(GradedGroupEditor,{ref:el=>this._editors[i]=el,...group,apiOptions:this.props.apiOptions,onChange:data=>this.change("gradedGroups",setArrayItem(gradedGroups,i,{...gradedGroups[i],...data}))},i))},this.addGroup=()=>{const groups=this.props.gradedGroups??[];this.change("gradedGroups",groups.concat([GradedGroupEditor.defaultProps]));};}}GradedGroupSetEditor.widgetName="graded-group-set";GradedGroupSetEditor.defaultProps=gradedGroupSetLogic.defaultWidgetOptions;const setArrayItem=(list,i,value)=>[...list.slice(0,i),value,...list.slice(i+1)];
1574
+ class GradedGroupSetEditor extends React.Component{UNSAFE_componentWillMount(){this._editors=[];}render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[this.renderGroups(),jsxRuntimeExports.jsx("button",{onClick:this.addGroup,disabled:editingDisabled,children:"Add group"})]})}constructor(...args){super(...args),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.getSaveWarnings=()=>{return [].concat(...this._editors.map(editor=>editor?editor.getSaveWarnings():[]))},this.serialize=()=>{return {gradedGroups:this.props.gradedGroups}},this.renderGroups=()=>{const gradedGroups=this.props.gradedGroups??[];return gradedGroups.map((group,i)=>jsxRuntimeExports.jsx(GradedGroupEditor,{ref:el=>this._editors[i]=el,...group,apiOptions:this.props.apiOptions,onChange:data=>this.change("gradedGroups",setArrayItem(gradedGroups,i,{...gradedGroups[i],...data}))},i))},this.addGroup=()=>{const groups=this.props.gradedGroups??[];this.change("gradedGroups",groups.concat([GradedGroupEditor.defaultProps]));};}}GradedGroupSetEditor.defaultProps=gradedGroupSetLogic.defaultWidgetOptions;const setArrayItem=(list,i,value)=>[...list.slice(0,i),value,...list.slice(i+1)];
1575
1575
 
1576
1576
  const{ButtonGroup: ButtonGroup$6,RangeInput: RangeInput$5}=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)}}changeRulerLabel(e){this.props.onChange({rulerLabel:e.target.value});}changeRulerTicks(e){this.props.onChange({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&"key"in e&&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 choices.map(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??0)<=450&&(image.height??0)<=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:gridStep.map(function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=this.state.rangeTextbox.map(range=>range.map(Number));const step=this.state.stepTextbox.map(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.props.onChange({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.props.onChange({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:[this.props.editableSettings.includes("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$5,{id:"canvas-size",value:this.props.box,onChange:box=>{this.props.onChange({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),this.props.editableSettings.includes("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$5,{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$5,{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$5,{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$5,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),this.props.editableSettings.includes("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$5,{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:value=>this.props.onChange({markings:value})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})})]}),this.props.editableSettings.includes("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,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),this.props.editableSettings.includes("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.props.onChange({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.props.onChange({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:[1,2,4,8,10,16].map(function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();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};
1577
1577
 
1578
- const{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,options:{graph:this.props.graph,correct:this.props.correct,availableTypes:[...this.props.availableTypes]},userInput:this.props.correct,handleUserInput:userInput=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct});},trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};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,{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===true,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:newProps=>this.props.onChange({graph:{...this.props.graph,...newProps}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:GrapherUtil$1.allTypes.map(typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!newAvailableTypes.includes(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.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1578
+ const{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,options:{graph:this.props.graph,correct:this.props.correct,availableTypes:[...this.props.availableTypes]},userInput:this.props.correct,handleUserInput:userInput=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct});},trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};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,{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===true,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:newProps=>this.props.onChange({graph:{...this.props.graph,...newProps}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:GrapherUtil$1.allTypes.map(typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!newAvailableTypes.includes(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.defaultProps=grapherLogic.defaultWidgetOptions;
1579
1579
 
1580
- class GroupEditor extends React.Component{serialize(){invariant(this.editor.current,"cannot serialize GroupEditor without Editor");return {...this.editor.current.serialize()}}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,onChange:this.props.onChange})})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()};}}GroupEditor.propTypes={content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GroupEditor.widgetName="group";GroupEditor.defaultProps=groupLogic.defaultWidgetOptions;
1580
+ class GroupEditor extends React.Component{serialize(){invariant(this.editor.current,"cannot serialize GroupEditor without Editor");return {...this.editor.current.serialize()}}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,onChange:this.props.onChange})})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()};}}GroupEditor.propTypes={content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GroupEditor.defaultProps=groupLogic.defaultWidgetOptions;
1581
1581
 
1582
- 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 deprecatedChangeableChange.apply(this,args)};}}class PairsEditor extends React.Component{render(){const editors=this.props.pairs.map((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 deprecatedChangeableChange.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);};}}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,{pairs:this.props.settings??[],onChange:this.handleSettingsChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Width:",jsxRuntimeExports.jsx(BlurInput,{value:String(this.props.width),onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("label",{children:["Height:",jsxRuntimeExports.jsx(BlurInput,{value:String(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 deprecatedChangeableChange.apply(this,args)},this.handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}IframeEditor.widgetName="iframe";IframeEditor.defaultProps=iframeLogic.defaultWidgetOptions;
1582
+ 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 deprecatedChangeableChange.apply(this,args)};}}class PairsEditor extends React.Component{render(){const editors=this.props.pairs.map((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 deprecatedChangeableChange.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);};}}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,{pairs:this.props.settings??[],onChange:this.handleSettingsChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Width:",jsxRuntimeExports.jsx(BlurInput,{value:String(this.props.width),onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("label",{children:["Height:",jsxRuntimeExports.jsx(BlurInput,{value:String(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 deprecatedChangeableChange.apply(this,args)},this.handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}IframeEditor.defaultProps=iframeLogic.defaultWidgetOptions;
1583
1583
 
1584
1584
  const{SvgImage}=components;function ImagePreview({src,alt,width,height,wbTheme}){return jsxRuntimeExports.jsx("div",{className:"perseus-image-preview-container","data-testid":"image-preview-container","data-wb-theme":wbTheme,children:jsxRuntimeExports.jsx(SvgImage,{src:src,alt:alt,width:width,height:height,allowZoom:false})})}
1585
1585
 
@@ -1603,7 +1603,7 @@ const MIN_ALT_TEXT_LENGTH=8;const MAX_ALT_TEXT_LENGTH=125;const altTextTooLongEr
1603
1603
 
1604
1604
  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);function ImageUrlInput({backgroundImage,onChange}){const uniqueId=React__default.useId();const urlId=`${uniqueId}-url`;const[urlFieldValue,setUrlFieldValue]=React__default.useState(backgroundImage.url||"");const[backgroundImageError,setBackgroundImageError]=React__default.useState(null);React__default.useEffect(()=>{setUrlFieldValue(backgroundImage.url||"");},[backgroundImage.url]);function setUrl(url,width,height){const image={...backgroundImage};image.url=url;image.width=width;image.height=height;const box=[image.width,image.height];onChange({backgroundImage:image,box:box});}async function onUrlChange(url){setBackgroundImageError(null);if(!url){setUrl(url,0,0);return}if(url===backgroundImage.url){return}if(url&&!INTERNALLY_HOSTED_URL_RE.test(url)){setBackgroundImageError("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}try{const size=await Util.getImageSizeModern(url);setUrl(url,size[0],size[1]);}catch(error){setBackgroundImageError(`There was an error loading the image URL: ${JSON.stringify(error,null,2)}`);}}return jsxRuntimeExports.jsx(LabeledField,{label:"Image URL",description:"Paste an image or graphie image URL.",field:jsxRuntimeExports.jsx(TextField,{id:urlId,value:urlFieldValue,onBlur:e=>onUrlChange(e.target.value),onChange:value=>setUrlFieldValue(value)}),errorMessage:backgroundImageError,styles:wbFieldStylesWithDescription})}
1605
1605
 
1606
- class ImageEditor extends React.Component{serialize(){return EditorJsonify.serialize.call(this)}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageUrlInput,{...this.props}),jsxRuntimeExports.jsx(ImageSettings,{...this.props})]})}}ImageEditor.displayName="ImageEditor";ImageEditor.widgetName="image";ImageEditor.defaultProps=imageLogic.defaultWidgetOptions;
1606
+ class ImageEditor extends React.Component{serialize(){return EditorJsonify.serialize.call(this)}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ImageUrlInput,{...this.props}),jsxRuntimeExports.jsx(ImageSettings,{...this.props})]})}}ImageEditor.displayName="ImageEditor";ImageEditor.defaultProps=imageLogic.defaultWidgetOptions;
1607
1607
 
1608
1608
  function Heading({title,isOpen,isCollapsible,onToggle}){return jsxRuntimeExports.jsx(Clickable,{style:[styles$J.container,!isCollapsible&&styles$J.notClickable],disabled:!isCollapsible,onClick:()=>isCollapsible&&onToggle?.(!isOpen),children:()=>jsxRuntimeExports.jsxs(View,{style:styles$J.heading,children:[jsxRuntimeExports.jsx(BodyText,{size:"small",weight:"bold",tag:"span",children:title}),isCollapsible&&jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:isOpen})]})})}const styles$J=StyleSheet.create({container:{marginBlockStart:spacing.small_12,marginInline:-10,backgroundColor:semanticColor.core.background.neutral.subtle,padding:spacing.xSmall_8,width:"calc(100% + 20px)"},heading:{flexDirection:"row",justifyContent:"space-between",userSelect:"none"},notClickable:{color:"inherit",cursor:"default"}});
1609
1609
 
@@ -1613,9 +1613,9 @@ function ToggleButton({selected,onClick,disabled=false,role="radio",children,sty
1613
1613
 
1614
1614
  var styles$H = {"field":"perseus_SjB5EkqY","labelRow":"perseus_kGIonNza","inlineField":"perseus_AjUqaLV1"};
1615
1615
 
1616
- const{NumberInput: NumberInput$b,TextInput: TextInput$2}=components;const{firstNumericalParse}=Util;const answerFormButtons=[{title:"Integers",value:"integer",content:"6"},{title:"Decimals",value:"decimal",content:"0.75"},{title:"Proper fractions",value:"proper",content:"⅗"},{title:"Improper fractions",value:"improper",content:"⁷⁄₄"},{title:"Mixed numbers",value:"mixed",content:"1¾"},{title:"Numbers with π",value:"pi",content:"π"}];const initAnswer=status=>{return {value:null,status:status,message:"",simplify:"required",answerForms:[],strict:false,maxError:null}};class NumericInputEditor extends React.Component{render(){const answers=this.props.answers;const editingDisabled=this.props.apiOptions.editingDisabled;const unsimplifiedAnswers=i=>jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[answers[i]["status"]!=="correct"&&jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Unsimplified answers are irrelevant for this status"}),answers[i]["status"]==="correct"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Unsimplified answers are"}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "ungraded". 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 after)'}),jsxRuntimeExports.jsx("p",{children:'Select "accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsxs("p",{children:['Select "wrong" ',jsxRuntimeExports.jsx("em",{children:"only"})," if we are specifically assessing the ability to simplify."]})]})]}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Unsimplified answers are",disabled:editingDisabled,selectedValue:answers[i]["simplify"],onChange:value=>this.updateAnswer(i,{simplify:value}),options:[{value:"required",label:"Ungraded"},{value:"optional",label:"Accepted"},{value:"enforced",label:"Wrong"}]})]})]});const suggestedAnswerTypes=i=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Possible answer formats"}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:'Formats will be autoselected for you based on the given answer; to show no suggested formats and accept all types, simply have a decimal/integer be the answer. Values with π will have format "pi", and values that are fractions will have some subset (mixed will be "mixed" and "proper"; improper/proper will both be "improper" and "proper"). If you would like to specify that it is only a proper fraction (or only a mixed/improper fraction), deselect the other format. Except for specific cases, you should not need to change the autoselected formats.'}),jsxRuntimeExports.jsxs("p",{children:["To restrict the answer to ",jsxRuntimeExports.jsx("em",{children:"only"}),' an improper fraction (i.e. 7/4), select the improper fraction and toggle "strict" to true. This ',jsxRuntimeExports.jsx("b",{children:"will not"})," accept 1.75 as an answer."," "]}),jsxRuntimeExports.jsx("p",{children:"Unless you are testing that specific skill, please do not restrict the answer format."})]})]}),jsxRuntimeExports.jsx(ToggleButtonGroup,{"aria-label":"Possible answer formats",disabled:editingDisabled,selectedValues:answers[i]["answerForms"]??[],onToggle:value=>this.onToggleAnswerForm(i,value),options:answerFormButtons.map(format=>({value:format.value,label:format.content,ariaLabel:format.title}))})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Answer formats are"}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Answer formats are",disabled:editingDisabled,selectedValue:answers[i]["strict"]?"required":"suggested",onChange:value=>this.updateAnswer(i,{strict:value==="required"}),options:[{value:"suggested",label:"Suggested"},{value:"required",label:"Required"}]})]})]});const inputSize=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Width"}),jsxRuntimeExports.jsx(InfoTip,{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(SegmentedControl,{"aria-label":"Width",disabled:editingDisabled,selectedValue:this.props.size,onChange:value=>this.change("size")(value),options:[{value:"normal",label:"Normal (80px)"},{value:"small",label:"Small (40px)"}]})]});const labelText=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Answer Field Aria label"}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Text to describe the Answer Field for screenreader users."})})]}),jsxRuntimeExports.jsx(TextInput$2,{labelText:"aria label",value:this.props.labelText,onChange:this.change("labelText")})]});const coefficientCheck=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Number style"}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"A coefficient style number allows the student to use - for -1 and an empty string to mean 1."})})]}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Number style",disabled:editingDisabled,selectedValue:this.props.coefficient?"coefficient":"standard",onChange:value=>this.props.onChange({coefficient:value==="coefficient"}),options:[{value:"standard",label:"Standard"},{value:"coefficient",label:"Coefficient"}]})]});const instructions={wrong:"(address the mistake/misconception)",ungraded:"(explain in detail to avoid confusion)",correct:"(reinforce the user's understanding)"};const generateInputAnswerEditors=()=>answers.map((answer,i)=>{const editor=jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:answer.message||"",placeholder:"Why is this answer "+answer.status+"? "+instructions[answer.status],widgetEnabled:false,onChange:newProps=>{if("content"in newProps){this.updateAnswer(i,{message:newProps.content});}}});const statusProper=answer.status.charAt(0).toUpperCase()+answer.status.slice(1);const answerFormat=(answer.answerForms||[]).at(-1);const answerString=KhanMath.toNumericString(answer.value??0,answerFormat);const answerRangeText=answer.maxError?`\xb1 ${KhanMath.toNumericString(answer.maxError,answerFormat)}`:"";const answerHeading=answer.value===null?"New Answer":`${statusProper} answer: ${answerString} ${answerRangeText}`;return jsxRuntimeExports.jsx("div",{className:"perseus-widget-row answer-option",children:jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:this.state.showAnswerDetails[i],onToggle:()=>{this.onToggleAnswers(i);},header:jsxRuntimeExports.jsx(BodyText,{weight:"bold",tag:"span",children:answerHeading}),children:[jsxRuntimeExports.jsxs("div",{className:"input-answer-editor-value-container"+(answer.maxError?" with-max-error":""),children:[jsxRuntimeExports.jsxs(View,{tag:"label",className:styles$H.inlineField,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"User input"}),jsxRuntimeExports.jsx(NumberInput$b,{value:answer.value,className:"numeric-input-value",placeholder:"answer",format:_.last(answer.answerForms||[]),onFormatChange:(newValue,format)=>{let forms;if(format==="pi"){forms=["pi"];}else if(format==="mixed"){forms=["proper","mixed"];}else if(format==="proper"||format==="improper"){forms=["proper","improper"];}this.updateAnswer(i,{value:firstNumericalParse(newValue),answerForms:forms});},onChange:newValue=>{this.updateAnswer(i,{value:firstNumericalParse(newValue)});}})]}),jsxRuntimeExports.jsx("span",{className:"max-error-plusmn",children:"±"}),jsxRuntimeExports.jsx(NumberInput$b,{className:"max-error-input-value",placeholder:0,value:answers[i]["maxError"],format:_.last(answer.answerForms||[]),onChange:this.updateAnswer(i,"maxError")})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Status"}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Status",disabled:editingDisabled,selectedValue:answers[i]["status"],onChange:value=>this.onEvaluationChange(i,value),options:[{value:"correct",label:"Correct"},{value:"wrong",label:"Wrong"},{value:"ungraded",label:"Ungraded"}]})]}),unsimplifiedAnswers(i),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"(Articles only) Message shown to user"}),editor]}),suggestedAnswerTypes(i),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,"aria-label":`Delete ${answerHeading}`,className:"delete-item-button",disabled:editingDisabled,onClick:()=>{this.onTrashAnswer(i);},kind:"tertiary",children:"Delete"})]})},i)});return jsxRuntimeExports.jsxs("div",{className:"perseus-input-number-editor",children:[jsxRuntimeExports.jsx(Heading,{title:"General Settings",isCollapsible:true,isOpen:this.state.showSettings,onToggle:this.onToggleHeading("Settings")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showSettings?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[inputSize,jsxRuntimeExports.jsxs("label",{children:["Text alignment",jsxRuntimeExports.jsx(TypedSingleSelect,{selectedValue:this.props.textAlign,onChange:value=>{this.props.onChange({textAlign:value});},options:{left:"Left",center:"Center",right:"Right"},placeholder:"Select text alignment"})]}),coefficientCheck,labelText]})}),jsxRuntimeExports.jsx(Heading,{title:"Answers",isCollapsible:true,isOpen:this.state.showAnswers,onToggle:this.onToggleHeading("Answers")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showAnswers?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[generateInputAnswerEditors(),jsxRuntimeExports.jsx(Button,{kind:"tertiary",disabled:editingDisabled,onClick:this.addAnswer,children:"Add new answer"})]})})]})}constructor(props){super(props),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.onToggleAnswers=answerIndex=>{const showAnswerDetails=this.state.showAnswerDetails.slice();showAnswerDetails[answerIndex]=!showAnswerDetails[answerIndex];this.setState({showAnswerDetails:showAnswerDetails});},this.onToggleAnswerForm=(answerIndex,answerForm)=>{let answerForms=[...this.props.answers[answerIndex]["answerForms"]??[]];const formSelected=answerForms.includes(answerForm);if(!formSelected){answerForms.push(answerForm);}else {answerForms=answerForms.filter(form=>form!==answerForm);}const updateFn=this.updateAnswer(answerIndex,"answerForms");if(updateFn){updateFn(answerForms);}},this.onToggleHeading=accordionName=>{return ()=>{const toggleName=`show${accordionName}`;const newState={...this.state};newState[toggleName]=!newState[toggleName];this.setState(newState);}},this.onTrashAnswer=choiceIndex=>{if(choiceIndex>=0&&choiceIndex<this.props.answers.length){const answers=this.props.answers.slice(0);answers.splice(choiceIndex,1);this.props.onChange({answers:answers});}},this.onSpace=(e,callback,...args)=>{if(e.key===" "){e.preventDefault();callback.apply(this,args);}},this.onStatusChange=choiceIndex=>{const statuses=["wrong","ungraded","correct"];const answers=this.props.answers;const i=statuses.indexOf(answers[choiceIndex].status);const newStatus=statuses[(i+1)%statuses.length];this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.onEvaluationChange=(choiceIndex,newStatus)=>{this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.updateAnswer=(choiceIndex,update)=>{if(!_.isObject(update)){return _.partial((choiceIndex,key,value)=>{const update={};update[key]=value;this.updateAnswer(choiceIndex,update);},choiceIndex,update)}let answers=[...this.props.answers];if(choiceIndex===answers.length){const lastAnswer=initAnswer(this.state.lastStatus);answers=answers.concat(lastAnswer);}answers[choiceIndex]=_.extend({},answers[choiceIndex],update);this.props.onChange({answers:answers});},this.addAnswer=()=>{const lastAnswer=initAnswer(this.state.lastStatus);const answers=this.props.answers.concat(lastAnswer);const showAnswerDetails=this.state.showAnswerDetails.concat(true);this.setState({showAnswerDetails:showAnswerDetails});this.props.onChange({answers:answers});},this.getSaveWarnings=()=>{const warnings=[];if(_.contains(_.pluck(this.props.answers,"value"),"")){warnings.push("One or more answers is empty");}this.props.answers.forEach((answer,i)=>{const formatError=answer.strict&&(!answer.answerForms||answer.answerForms.length===0);if(formatError){warnings.push(`Answer ${i+1} is set to string format `+"matching, but no format was selected");}});return warnings},this.serialize=()=>{return EditorJsonify.serialize.call(this)};this.state={lastStatus:"wrong",showAnswerDetails:Array(this.props.answers.length).fill(true),showSettings:true,showAnswers:true};}}NumericInputEditor.widgetName="numeric-input";NumericInputEditor.displayName="NumericInputEditor";NumericInputEditor.defaultProps={...numericInputLogic.defaultWidgetOptions};
1616
+ const{NumberInput: NumberInput$b,TextInput: TextInput$2}=components;const{firstNumericalParse}=Util;const answerFormButtons=[{title:"Integers",value:"integer",content:"6"},{title:"Decimals",value:"decimal",content:"0.75"},{title:"Proper fractions",value:"proper",content:"⅗"},{title:"Improper fractions",value:"improper",content:"⁷⁄₄"},{title:"Mixed numbers",value:"mixed",content:"1¾"},{title:"Numbers with π",value:"pi",content:"π"}];const initAnswer=status=>{return {value:null,status:status,message:"",simplify:"required",answerForms:[],strict:false,maxError:null}};class NumericInputEditor extends React.Component{render(){const answers=this.props.answers;const editingDisabled=this.props.apiOptions.editingDisabled;const unsimplifiedAnswers=i=>jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[answers[i]["status"]!=="correct"&&jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Unsimplified answers are irrelevant for this status"}),answers[i]["status"]==="correct"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Unsimplified answers are"}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "ungraded". 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 after)'}),jsxRuntimeExports.jsx("p",{children:'Select "accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsxs("p",{children:['Select "wrong" ',jsxRuntimeExports.jsx("em",{children:"only"})," if we are specifically assessing the ability to simplify."]})]})]}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Unsimplified answers are",disabled:editingDisabled,selectedValue:answers[i]["simplify"],onChange:value=>this.updateAnswer(i,{simplify:value}),options:[{value:"required",label:"Ungraded"},{value:"optional",label:"Accepted"},{value:"enforced",label:"Wrong"}]})]})]});const suggestedAnswerTypes=i=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Possible answer formats"}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:'Formats will be autoselected for you based on the given answer; to show no suggested formats and accept all types, simply have a decimal/integer be the answer. Values with π will have format "pi", and values that are fractions will have some subset (mixed will be "mixed" and "proper"; improper/proper will both be "improper" and "proper"). If you would like to specify that it is only a proper fraction (or only a mixed/improper fraction), deselect the other format. Except for specific cases, you should not need to change the autoselected formats.'}),jsxRuntimeExports.jsxs("p",{children:["To restrict the answer to ",jsxRuntimeExports.jsx("em",{children:"only"}),' an improper fraction (i.e. 7/4), select the improper fraction and toggle "strict" to true. This ',jsxRuntimeExports.jsx("b",{children:"will not"})," accept 1.75 as an answer."," "]}),jsxRuntimeExports.jsx("p",{children:"Unless you are testing that specific skill, please do not restrict the answer format."})]})]}),jsxRuntimeExports.jsx(ToggleButtonGroup,{"aria-label":"Possible answer formats",disabled:editingDisabled,selectedValues:answers[i]["answerForms"]??[],onToggle:value=>this.onToggleAnswerForm(i,value),options:answerFormButtons.map(format=>({value:format.value,label:format.content,ariaLabel:format.title}))})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Answer formats are"}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Answer formats are",disabled:editingDisabled,selectedValue:answers[i]["strict"]?"required":"suggested",onChange:value=>this.updateAnswer(i,{strict:value==="required"}),options:[{value:"suggested",label:"Suggested"},{value:"required",label:"Required"}]})]})]});const inputSize=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Width"}),jsxRuntimeExports.jsx(InfoTip,{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(SegmentedControl,{"aria-label":"Width",disabled:editingDisabled,selectedValue:this.props.size,onChange:value=>this.change("size")(value),options:[{value:"normal",label:"Normal (80px)"},{value:"small",label:"Small (40px)"}]})]});const labelText=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Answer Field Aria label"}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Text to describe the Answer Field for screenreader users."})})]}),jsxRuntimeExports.jsx(TextInput$2,{labelText:"aria label",value:this.props.labelText,onChange:this.change("labelText")})]});const coefficientCheck=jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsxs(View,{className:styles$H.labelRow,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Number style"}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"A coefficient style number allows the student to use - for -1 and an empty string to mean 1."})})]}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Number style",disabled:editingDisabled,selectedValue:this.props.coefficient?"coefficient":"standard",onChange:value=>this.props.onChange({coefficient:value==="coefficient"}),options:[{value:"standard",label:"Standard"},{value:"coefficient",label:"Coefficient"}]})]});const instructions={wrong:"(address the mistake/misconception)",ungraded:"(explain in detail to avoid confusion)",correct:"(reinforce the user's understanding)"};const generateInputAnswerEditors=()=>answers.map((answer,i)=>{const editor=jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:answer.message||"",placeholder:"Why is this answer "+answer.status+"? "+instructions[answer.status],widgetEnabled:false,onChange:newProps=>{if("content"in newProps){this.updateAnswer(i,{message:newProps.content});}}});const statusProper=answer.status.charAt(0).toUpperCase()+answer.status.slice(1);const answerFormat=(answer.answerForms||[]).at(-1);const answerString=KhanMath.toNumericString(answer.value??0,answerFormat);const answerRangeText=answer.maxError?`\xb1 ${KhanMath.toNumericString(answer.maxError,answerFormat)}`:"";const answerHeading=answer.value===null?"New Answer":`${statusProper} answer: ${answerString} ${answerRangeText}`;return jsxRuntimeExports.jsx("div",{className:"perseus-widget-row answer-option",children:jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:this.state.showAnswerDetails[i],onToggle:()=>{this.onToggleAnswers(i);},header:jsxRuntimeExports.jsx(BodyText,{weight:"bold",tag:"span",children:answerHeading}),children:[jsxRuntimeExports.jsxs("div",{className:"input-answer-editor-value-container"+(answer.maxError?" with-max-error":""),children:[jsxRuntimeExports.jsxs(View,{tag:"label",className:styles$H.inlineField,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"User input"}),jsxRuntimeExports.jsx(NumberInput$b,{value:answer.value,className:"numeric-input-value",placeholder:"answer",format:_.last(answer.answerForms||[]),onFormatChange:(newValue,format)=>{let forms;if(format==="pi"){forms=["pi"];}else if(format==="mixed"){forms=["proper","mixed"];}else if(format==="proper"||format==="improper"){forms=["proper","improper"];}this.updateAnswer(i,{value:firstNumericalParse(newValue),answerForms:forms});},onChange:newValue=>{this.updateAnswer(i,{value:firstNumericalParse(newValue)});}})]}),jsxRuntimeExports.jsx("span",{className:"max-error-plusmn",children:"±"}),jsxRuntimeExports.jsx(NumberInput$b,{className:"max-error-input-value",placeholder:0,value:answers[i]["maxError"],format:_.last(answer.answerForms||[]),onChange:this.updateAnswer(i,"maxError")})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"Status"}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Status",disabled:editingDisabled,selectedValue:answers[i]["status"],onChange:value=>this.onEvaluationChange(i,value),options:[{value:"correct",label:"Correct"},{value:"wrong",label:"Wrong"},{value:"ungraded",label:"Ungraded"}]})]}),unsimplifiedAnswers(i),jsxRuntimeExports.jsxs(View,{className:styles$H.field,children:[jsxRuntimeExports.jsx(BodyText,{weight:"semi",children:"(Articles only) Message shown to user"}),editor]}),suggestedAnswerTypes(i),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,"aria-label":`Delete ${answerHeading}`,className:"delete-item-button",disabled:editingDisabled,onClick:()=>{this.onTrashAnswer(i);},kind:"tertiary",children:"Delete"})]})},i)});return jsxRuntimeExports.jsxs("div",{className:"perseus-input-number-editor",children:[jsxRuntimeExports.jsx(Heading,{title:"General Settings",isCollapsible:true,isOpen:this.state.showSettings,onToggle:this.onToggleHeading("Settings")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showSettings?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[inputSize,jsxRuntimeExports.jsxs("label",{children:["Text alignment",jsxRuntimeExports.jsx(TypedSingleSelect,{selectedValue:this.props.textAlign,onChange:value=>{this.props.onChange({textAlign:value});},options:{left:"Left",center:"Center",right:"Right"},placeholder:"Select text alignment"})]}),coefficientCheck,labelText]})}),jsxRuntimeExports.jsx(Heading,{title:"Answers",isCollapsible:true,isOpen:this.state.showAnswers,onToggle:this.onToggleHeading("Answers")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showAnswers?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[generateInputAnswerEditors(),jsxRuntimeExports.jsx(Button,{kind:"tertiary",disabled:editingDisabled,onClick:this.addAnswer,children:"Add new answer"})]})})]})}constructor(props){super(props),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this.onToggleAnswers=answerIndex=>{const showAnswerDetails=this.state.showAnswerDetails.slice();showAnswerDetails[answerIndex]=!showAnswerDetails[answerIndex];this.setState({showAnswerDetails:showAnswerDetails});},this.onToggleAnswerForm=(answerIndex,answerForm)=>{let answerForms=[...this.props.answers[answerIndex]["answerForms"]??[]];const formSelected=answerForms.includes(answerForm);if(!formSelected){answerForms.push(answerForm);}else {answerForms=answerForms.filter(form=>form!==answerForm);}const updateFn=this.updateAnswer(answerIndex,"answerForms");if(updateFn){updateFn(answerForms);}},this.onToggleHeading=accordionName=>{return ()=>{const toggleName=`show${accordionName}`;const newState={...this.state};newState[toggleName]=!newState[toggleName];this.setState(newState);}},this.onTrashAnswer=choiceIndex=>{if(choiceIndex>=0&&choiceIndex<this.props.answers.length){const answers=this.props.answers.slice(0);answers.splice(choiceIndex,1);this.props.onChange({answers:answers});}},this.onSpace=(e,callback,...args)=>{if(e.key===" "){e.preventDefault();callback.apply(this,args);}},this.onStatusChange=choiceIndex=>{const statuses=["wrong","ungraded","correct"];const answers=this.props.answers;const i=statuses.indexOf(answers[choiceIndex].status);const newStatus=statuses[(i+1)%statuses.length];this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.onEvaluationChange=(choiceIndex,newStatus)=>{this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.updateAnswer=(choiceIndex,update)=>{if(!_.isObject(update)){return _.partial((choiceIndex,key,value)=>{const update={};update[key]=value;this.updateAnswer(choiceIndex,update);},choiceIndex,update)}let answers=[...this.props.answers];if(choiceIndex===answers.length){const lastAnswer=initAnswer(this.state.lastStatus);answers=answers.concat(lastAnswer);}answers[choiceIndex]=_.extend({},answers[choiceIndex],update);this.props.onChange({answers:answers});},this.addAnswer=()=>{const lastAnswer=initAnswer(this.state.lastStatus);const answers=this.props.answers.concat(lastAnswer);const showAnswerDetails=this.state.showAnswerDetails.concat(true);this.setState({showAnswerDetails:showAnswerDetails});this.props.onChange({answers:answers});},this.getSaveWarnings=()=>{const warnings=[];if(_.contains(_.pluck(this.props.answers,"value"),"")){warnings.push("One or more answers is empty");}this.props.answers.forEach((answer,i)=>{const formatError=answer.strict&&(!answer.answerForms||answer.answerForms.length===0);if(formatError){warnings.push(`Answer ${i+1} is set to string format `+"matching, but no format was selected");}});return warnings},this.serialize=()=>{return EditorJsonify.serialize.call(this)};this.state={lastStatus:"wrong",showAnswerDetails:Array(this.props.answers.length).fill(true),showSettings:true,showAnswers:true};}}NumericInputEditor.displayName="NumericInputEditor";NumericInputEditor.defaultProps={...numericInputLogic.defaultWidgetOptions};
1617
1617
 
1618
- class InputNumberEditor extends NumericInputEditor{}InputNumberEditor.widgetName="input-number";
1618
+ class InputNumberEditor extends NumericInputEditor{}
1619
1619
 
1620
1620
  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"};
1621
1621
 
@@ -1645,7 +1645,7 @@ class PointEditor extends React.Component{render(){const{TeX}=Dependencies.getDe
1645
1645
 
1646
1646
  class RectangleEditor extends React.Component{render(){const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Bottom left: ",jsxRuntimeExports.jsx(TeX,{children:"\\Large("}),jsxRuntimeExports.jsx(MathquillInput,{value:this.props.coordX,onChange:this.change("coordX")}),jsxRuntimeExports.jsx(TeX,{children:","})," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.coordY,onChange:this.change("coordY")}),jsxRuntimeExports.jsx(TeX,{children:"\\Large)"})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Width:"," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.width,onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Height:"," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.height,onChange:this.change("height")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(ColorPicker,{value:this.props.color,lightColors:true,onChange:this.change("color")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:"You want a border? Sorry, draw your own."})]})}constructor(...args){super(...args),this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)};}}RectangleEditor.defaultProps={coordX:"-5",coordY:"5",width:"2",height:"3",color:KhanColors.LIGHT_BLUE};
1647
1647
 
1648
- const{unescapeMathMode}=Util;const defaultOptionsByElementType={point:PointEditor.defaultProps,line:LineEditor.defaultProps,"movable-point":MovablePointEditor.defaultProps,"movable-line":MovableLineEditor.defaultProps,function:FunctionEditor.defaultProps,parametric:ParametricEditor.defaultProps,label:LabelEditor.defaultProps,rectangle:RectangleEditor.defaultProps};class InteractionEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({usedVarSubscripts:this._getAllVarSubscripts(nextProps.elements),usedFunctionNames:this._getAllFunctionNames(nextProps.elements)});}_getAllVarSubscripts(elements){const movableLines=elements.filter(element=>element.type==="movable-line");return elements.filter(element=>element.type==="movable-point").map(element=>element.options.varSubscript).concat(movableLines.map(element=>element.options.startSubscript)).concat(movableLines.map(element=>element.options.endSubscript))}_getAllFunctionNames(elements){return elements.filter(element=>element.type==="function").map(element=>element.options.funcName)}render(){const{TeX}=Dependencies.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})})]}),this.props.elements.map((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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(MovablePointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(MovableLineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(PointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(LineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(FunctionEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="parametric"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsx("span",{children:"Parametric"}),onUp:n===0?null:()=>this._moveElementUp(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(ParametricEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(LabelEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(RectangleEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}}),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=>{const{step,...rest}=newProps;this.props.onChange({graph:{...this.props.graph,...rest,tickStep: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:{...defaultOptionsByElementType[elementType]}};let nextSubscript;if(elementType==="movable-point"){nextSubscript=Math.max(...this.state.usedVarSubscripts,-1)+1;newElement.options.varSubscript=nextSubscript;}else if(elementType==="movable-line"){nextSubscript=Math.max(...this.state.usedVarSubscripts,-1)+1;newElement.options.startSubscript=nextSubscript;newElement.options.endSubscript=nextSubscript+1;}else if(elementType==="function"){const nextLetter=String.fromCharCode(Math.max(...this.state.usedFunctionNames.map(c=>c.charCodeAt(0)),"e".charCodeAt(0))+1);newElement.options.funcName=nextLetter;}this.props.onChange({elements:this.props.elements.concat(newElement)});},this._deleteElement=index=>{const element=this.props.elements[index];this.props.onChange({elements:this.props.elements.filter(e=>e!==element)});},this._moveElementUp=index=>{const element=this.props.elements[index];const newElements=this.props.elements.filter(e=>e!==element);newElements.splice(index-1,0,element);this.props.onChange({elements:newElements});},this._moveElementDown=index=>{const element=this.props.elements[index];const newElements=this.props.elements.filter(e=>e!==element);newElements.splice(index+1,0,element);this.props.onChange({elements:newElements});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}InteractionEditor.widgetName="interaction";InteractionEditor.defaultProps=interactionLogic.defaultWidgetOptions;
1648
+ const{unescapeMathMode}=Util;const defaultOptionsByElementType={point:PointEditor.defaultProps,line:LineEditor.defaultProps,"movable-point":MovablePointEditor.defaultProps,"movable-line":MovableLineEditor.defaultProps,function:FunctionEditor.defaultProps,parametric:ParametricEditor.defaultProps,label:LabelEditor.defaultProps,rectangle:RectangleEditor.defaultProps};class InteractionEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({usedVarSubscripts:this._getAllVarSubscripts(nextProps.elements),usedFunctionNames:this._getAllFunctionNames(nextProps.elements)});}_getAllVarSubscripts(elements){const movableLines=elements.filter(element=>element.type==="movable-line");return elements.filter(element=>element.type==="movable-point").map(element=>element.options.varSubscript).concat(movableLines.map(element=>element.options.startSubscript)).concat(movableLines.map(element=>element.options.endSubscript))}_getAllFunctionNames(elements){return elements.filter(element=>element.type==="function").map(element=>element.options.funcName)}render(){const{TeX}=Dependencies.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})})]}),this.props.elements.map((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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(MovablePointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(MovableLineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(PointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(LineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(FunctionEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="parametric"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsx("span",{children:"Parametric"}),onUp:n===0?null:()=>this._moveElementUp(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(ParametricEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(LabelEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({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(n),onDown:n===this.props.elements.length-1?null:()=>this._moveElementDown(n),onDelete:()=>this._deleteElement(n),children:jsxRuntimeExports.jsx(RectangleEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));Object.assign(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}}),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=>{const{step,...rest}=newProps;this.props.onChange({graph:{...this.props.graph,...rest,tickStep: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:{...defaultOptionsByElementType[elementType]}};let nextSubscript;if(elementType==="movable-point"){nextSubscript=Math.max(...this.state.usedVarSubscripts,-1)+1;newElement.options.varSubscript=nextSubscript;}else if(elementType==="movable-line"){nextSubscript=Math.max(...this.state.usedVarSubscripts,-1)+1;newElement.options.startSubscript=nextSubscript;newElement.options.endSubscript=nextSubscript+1;}else if(elementType==="function"){const nextLetter=String.fromCharCode(Math.max(...this.state.usedFunctionNames.map(c=>c.charCodeAt(0)),"e".charCodeAt(0))+1);newElement.options.funcName=nextLetter;}this.props.onChange({elements:this.props.elements.concat(newElement)});},this._deleteElement=index=>{const element=this.props.elements[index];this.props.onChange({elements:this.props.elements.filter(e=>e!==element)});},this._moveElementUp=index=>{const element=this.props.elements[index];const newElements=this.props.elements.filter(e=>e!==element);newElements.splice(index-1,0,element);this.props.onChange({elements:newElements});},this._moveElementDown=index=>{const element=this.props.elements[index];const newElements=this.props.elements.filter(e=>e!==element);newElements.splice(index+1,0,element);this.props.onChange({elements:newElements});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}InteractionEditor.defaultProps=interactionLogic.defaultWidgetOptions;
1649
1649
 
1650
1650
  var styles$F = {"singleSelectShort":"perseus_wAZzFxEx","row":"perseus_6FquBkGo"};
1651
1651
 
@@ -1800,7 +1800,7 @@ const StartCoordsSettingsInner=props=>{const{type,range,step,allowReflexAngles,o
1800
1800
 
1801
1801
  function toTrio(pointLabels){return [pointLabels[0]??"",pointLabels[1]??"",pointLabels[2]??""]}function toPair(pointLabels){return [pointLabels[0]??"",pointLabels[1]??""]}function toArray(pointLabels){return [...pointLabels]}function reshapePointLabelsForGraphType(pointLabels,graph,correct){if(!graph?.type||!correct){return null}let nextGraph;let nextCorrect=correct;switch(graph.type){case "angle":case "quadratic":{const reshaped=toTrio(pointLabels);nextGraph={...graph,pointLabels:reshaped};if(correct.type===graph.type){nextCorrect={...correct,pointLabels:reshaped};}break}case "absolute-value":case "linear":case "ray":{const reshaped=toPair(pointLabels);nextGraph={...graph,pointLabels:reshaped};if(correct.type===graph.type){nextCorrect={...correct,pointLabels:reshaped};}break}case "circle":case "exponential":case "linear-system":case "logarithm":case "point":case "polygon":case "segment":case "sinusoid":case "tangent":{const reshaped=toArray(pointLabels);nextGraph={...graph,pointLabels:reshaped};if(correct.type===graph.type){nextCorrect={...correct,pointLabels:reshaped};}break}case "vector":case "none":return null}return {graph:nextGraph,correct:nextCorrect}}
1802
1802
 
1803
- const InteractiveGraph=InteractiveGraphWidget.widget;class InteractiveGraphEditor extends React.Component{serialize(){const json=_.pick(this.props,"step","backgroundImage","markings","labels","labelLocation","showProtractor","showTooltips","range","showAxisArrows","showAxisTicks","gridStep","snapStep","lockedFigures","fullGraphAriaLabel","fullGraphAriaDescription");const graph=this.refs.graph;if(graph){const correct=graph&&graph.getUserInput();_.extend(json,{graph:{type:correct.type,startCoords:getStartCoords(this.props.graph),..."pointLabels"in this.props.graph&&this.props.graph.pointLabels?{pointLabels:this.props.graph.pointLabels}:{},..."showPointLabels"in this.props.graph&&this.props.graph.showPointLabels?{showPointLabels:this.props.graph.showPointLabels}:{}},correct:correct});_.each(["allowReflexAngles","angleOffsetDeg","numPoints","numSides","numSegments","showAngles","showSides","snapTo","snapDegrees"],function(key){if(_.has(correct,key)){json.graph[key]=correct[key];}});}else {_.extend(json,{graph:this.props.graph,correct:this.props.correct});}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.type===this.props.graph?.type?this.props.correct:this.props.graph;const graphProps={ref:"graph",options:{box:this.props.box,range:this.props.range,showAxisArrows:this.props.showAxisArrows,showAxisTicks:this.props.showAxisTicks,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},static:this.props.apiOptions?.editingDisabled??false,trackInteraction:function(){},userInput:this.props.static===true&&correct!=null&&"showPointLabels"in correct?{...correct,showPointLabels:false}:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(this.props.static===true&&newGraph!=null&&"showPointLabels"in newGraph){newGraph={...newGraph,showPointLabels:"showPointLabels"in correct?correct.showPointLabels:undefined};}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",labelSize:"medium",children:jsxRuntimeExports.jsx(GraphTypeSelector,{disabled:this.props.apiOptions?.editingDisabled??false,graphType:this.props.graph?.type??"none",onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",editingDisabled:this.props.apiOptions?.editingDisabled??false,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==="vector"&&jsxRuntimeExports.jsx(VectorAnswerOptions,{correct:this.props.correct,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.static&&this.props.graph?.type&&this.props.graph.type!=="vector"&&this.props.graph.type!=="none"&&jsxRuntimeExports.jsx(ShowPointLabelsToggle,{showPointLabels:this.props.graph.showPointLabels===true,pointLabels:this.props.graph.pointLabels,onChange:this.changeShowPointLabels}),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,editingDisabled:this.props.apiOptions?.editingDisabled??false,onChange:this.changeStartCoords,onChangePointLabels:this.changePointLabels}),jsxRuntimeExports.jsx(InteractiveGraphSRTree,{graphId:graphId,correct:this.props.correct,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,lockedFigures:this.props.lockedFigures,editingDisabled:this.props.apiOptions?.editingDisabled??false}),jsxRuntimeExports.jsx(InteractiveGraphSettings,{box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.range,showAxisArrows:this.props.showAxisArrows,showAxisTicks:this.props.showAxisTicks,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,apiOptions:this.props.apiOptions}),jsxRuntimeExports.jsx(LockedFiguresSection,{figures:this.props.lockedFigures,onChange:this.props.onChange,apiOptions:this.props.apiOptions})]})})}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.changePointLabels=pointLabels=>{const next=reshapePointLabelsForGraphType(pointLabels,this.props.graph,this.props.correct);if(next){this.props.onChange(next);}},this.changeShowPointLabels=showPointLabels=>{const{graph,correct}=this.props;if(graph===undefined||correct===undefined){return}const newGraph=withShowPointLabels(graph,showPointLabels);const newCorrect=withShowPointLabels(correct,showPointLabels);if(newGraph===undefined||newCorrect===undefined){return}this.props.onChange({graph:newGraph,correct:newCorrect});},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.");}if(this.props.graph?.type==="exponential"&&this.props.graph.startCoords!=null){const{coords,asymptote}=this.props.graph.startCoords;const asymptoteY=asymptote;const minY=Math.min(coords[0][1],coords[1][1]);const maxY=Math.max(coords[0][1],coords[1][1]);if(asymptoteY>=minY&&asymptoteY<=maxY){issues.push("The exponential start asymptote must not fall between or on the curve's start points.");}}if(this.props.graph?.type==="logarithm"&&this.props.graph.startCoords!=null){const{coords,asymptote}=this.props.graph.startCoords;const asymptoteX=asymptote;const minX=Math.min(coords[0][0],coords[1][0]);const maxX=Math.max(coords[0][0],coords[1][0]);if(asymptoteX>=minX&&asymptoteX<=maxX){issues.push("The logarithm start asymptote must not fall between or on the curve's start points.");}}return issues};}}InteractiveGraphEditor.widgetName="interactive-graph";InteractiveGraphEditor.bestPractices={url:"https://khanacademy.atlassian.net/wiki/spaces/LC/pages/3295281289/Interactive+Graph+Widget#Adding-a-new-Interactive-Graph-Widget",label:"Interactive Graph best practices"};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};case "absolute-value":invariant(b.type==="absolute-value");return {...a,...b};case "exponential":invariant(b.type==="exponential");return {...a,...b};case "tangent":invariant(b.type==="tangent");return {...a,...b};case "logarithm":invariant(b.type==="logarithm");return {...a,...b};case "vector":invariant(b.type==="vector");return {...a,...b};default:throw new UnreachableCaseError(a)}}function withShowPointLabels(graph,showPointLabels){switch(graph.type){case "absolute-value":case "angle":case "circle":case "exponential":case "linear":case "linear-system":case "logarithm":case "point":case "polygon":case "quadratic":case "ray":case "segment":case "sinusoid":case "tangent":return {...graph,showPointLabels};case "none":case "vector":return undefined;default:throw new UnreachableCaseError(graph)}}
1803
+ const InteractiveGraph=InteractiveGraphWidget.widget;class InteractiveGraphEditor extends React.Component{serialize(){const json=_.pick(this.props,"step","backgroundImage","markings","labels","labelLocation","showProtractor","showTooltips","range","showAxisArrows","showAxisTicks","gridStep","snapStep","lockedFigures","fullGraphAriaLabel","fullGraphAriaDescription");const graph=this.refs.graph;if(graph){const correct=graph&&graph.getUserInput();_.extend(json,{graph:{type:correct.type,startCoords:getStartCoords(this.props.graph),..."pointLabels"in this.props.graph&&this.props.graph.pointLabels?{pointLabels:this.props.graph.pointLabels}:{},..."showPointLabels"in this.props.graph&&this.props.graph.showPointLabels?{showPointLabels:this.props.graph.showPointLabels}:{}},correct:correct});_.each(["allowReflexAngles","angleOffsetDeg","numPoints","numSides","numSegments","showAngles","showSides","snapTo","snapDegrees"],function(key){if(_.has(correct,key)){json.graph[key]=correct[key];}});}else {_.extend(json,{graph:this.props.graph,correct:this.props.correct});}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.type===this.props.graph?.type?this.props.correct:this.props.graph;const graphProps={ref:"graph",options:{box:this.props.box,range:this.props.range,showAxisArrows:this.props.showAxisArrows,showAxisTicks:this.props.showAxisTicks,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},static:this.props.apiOptions?.editingDisabled??false,trackInteraction:function(){},userInput:this.props.static===true&&correct!=null&&"showPointLabels"in correct?{...correct,showPointLabels:false}:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(this.props.static===true&&newGraph!=null&&"showPointLabels"in newGraph){newGraph={...newGraph,showPointLabels:"showPointLabels"in correct?correct.showPointLabels:undefined};}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",labelSize:"medium",children:jsxRuntimeExports.jsx(GraphTypeSelector,{disabled:this.props.apiOptions?.editingDisabled??false,graphType:this.props.graph?.type??"none",onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",editingDisabled:this.props.apiOptions?.editingDisabled??false,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==="vector"&&jsxRuntimeExports.jsx(VectorAnswerOptions,{correct:this.props.correct,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.static&&this.props.graph?.type&&this.props.graph.type!=="vector"&&this.props.graph.type!=="none"&&jsxRuntimeExports.jsx(ShowPointLabelsToggle,{showPointLabels:this.props.graph.showPointLabels===true,pointLabels:this.props.graph.pointLabels,onChange:this.changeShowPointLabels}),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,editingDisabled:this.props.apiOptions?.editingDisabled??false,onChange:this.changeStartCoords,onChangePointLabels:this.changePointLabels}),jsxRuntimeExports.jsx(InteractiveGraphSRTree,{graphId:graphId,correct:this.props.correct,fullGraphAriaLabel:this.props.fullGraphAriaLabel,fullGraphAriaDescription:this.props.fullGraphAriaDescription,lockedFigures:this.props.lockedFigures,editingDisabled:this.props.apiOptions?.editingDisabled??false}),jsxRuntimeExports.jsx(InteractiveGraphSettings,{box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.range,showAxisArrows:this.props.showAxisArrows,showAxisTicks:this.props.showAxisTicks,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,apiOptions:this.props.apiOptions}),jsxRuntimeExports.jsx(LockedFiguresSection,{figures:this.props.lockedFigures,onChange:this.props.onChange,apiOptions:this.props.apiOptions})]})})}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.changePointLabels=pointLabels=>{const next=reshapePointLabelsForGraphType(pointLabels,this.props.graph,this.props.correct);if(next){this.props.onChange(next);}},this.changeShowPointLabels=showPointLabels=>{const{graph,correct}=this.props;if(graph===undefined||correct===undefined){return}const newGraph=withShowPointLabels(graph,showPointLabels);const newCorrect=withShowPointLabels(correct,showPointLabels);if(newGraph===undefined||newCorrect===undefined){return}this.props.onChange({graph:newGraph,correct:newCorrect});},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.");}if(this.props.graph?.type==="exponential"&&this.props.graph.startCoords!=null){const{coords,asymptote}=this.props.graph.startCoords;const asymptoteY=asymptote;const minY=Math.min(coords[0][1],coords[1][1]);const maxY=Math.max(coords[0][1],coords[1][1]);if(asymptoteY>=minY&&asymptoteY<=maxY){issues.push("The exponential start asymptote must not fall between or on the curve's start points.");}}if(this.props.graph?.type==="logarithm"&&this.props.graph.startCoords!=null){const{coords,asymptote}=this.props.graph.startCoords;const asymptoteX=asymptote;const minX=Math.min(coords[0][0],coords[1][0]);const maxX=Math.max(coords[0][0],coords[1][0]);if(asymptoteX>=minX&&asymptoteX<=maxX){issues.push("The logarithm start asymptote must not fall between or on the curve's start points.");}}return issues};}}InteractiveGraphEditor.bestPractices={url:"https://khanacademy.atlassian.net/wiki/spaces/LC/pages/3295281289/Interactive+Graph+Widget#Adding-a-new-Interactive-Graph-Widget",label:"Interactive Graph best practices"};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};case "absolute-value":invariant(b.type==="absolute-value");return {...a,...b};case "exponential":invariant(b.type==="exponential");return {...a,...b};case "tangent":invariant(b.type==="tangent");return {...a,...b};case "logarithm":invariant(b.type==="logarithm");return {...a,...b};case "vector":invariant(b.type==="vector");return {...a,...b};default:throw new UnreachableCaseError(a)}}function withShowPointLabels(graph,showPointLabels){switch(graph.type){case "absolute-value":case "angle":case "circle":case "exponential":case "linear":case "linear-system":case "logarithm":case "point":case "polygon":case "quadratic":case "ray":case "segment":case "sinusoid":case "tangent":return {...graph,showPointLabels};case "none":case "vector":return undefined;default:throw new UnreachableCaseError(graph)}}
1804
1804
 
1805
1805
  const gray98="#FAFAFA";const gray95="#F0F1F2";const gray85="#D6D8DA";const gray76="#BABEC2";const gray68="#888D93";const gray41="#626569";const gray17="#21242C";
1806
1806
 
@@ -1833,23 +1833,23 @@ var styles$3 = {"imageRow":"perseus_-XexOs6i"};
1833
1833
 
1834
1834
  const SelectImage=({onChange,url,editingDisabled=false})=>jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(BodyText,{weight:"bold",tag:"span",children:"Image"}),jsxRuntimeExports.jsxs("div",{className:styles$3.imageRow,children:[jsxRuntimeExports.jsx(FormWrappedTextField$1,{placeholder:"URL",grow:1,onChange:e=>onChange(e.target.value),value:url}),jsxRuntimeExports.jsx(Button,{disabled:!url||editingDisabled,"aria-label":url?"":"Not implemented. Use the 'Add Image' button in "+"the editor to upload image, then copy the URL here.",onClick:()=>onChange(""),style:{minInlineSize:90},children:url?"Remove":"Upload"})]})]});
1835
1835
 
1836
- class LabelImageEditor extends React.Component{componentDidUpdate(prevProps){const coordsToMarkers={};prevProps.markers.forEach(marker=>coordsToMarkers[`${marker.x}.${marker.y}`]=marker);const newIndices=this.props.markers.map((marker,index)=>coordsToMarkers.hasOwnProperty(`${marker.x}.${marker.y}`)?-1:index).filter(index=>index!==-1);if(newIndices.length&&this._questionMarkers){this._questionMarkers.openDropdownForMarkerIndices(newIndices);}}serialize(){return EditorJsonify.serialize.call(this)}render(){const{choices,imageAlt,imageUrl,imageWidth,imageHeight,markers,multipleAnswers,hideChoicesFromInstructions,preferredPopoverDirection}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const imageSelected=imageUrl&&imageWidth>0&&imageHeight>0;return jsxRuntimeExports.jsxs("div",{className:styles$7.editor,children:[jsxRuntimeExports.jsx(SelectImage,{onChange:this.handleImageChange,url:imageUrl,editingDisabled:editingDisabled}),imageSelected&&jsxRuntimeExports.jsx(FormWrappedTextField$1,{placeholder:"Alt text (for screen readers)",onChange:e=>this.handleAltChange(e.target.value),value:imageAlt,width:"100%"}),jsxRuntimeExports.jsx(QuestionMarkers,{editingDisabled:editingDisabled,choices:choices,imageUrl:imageSelected?imageUrl:"",imageWidth:imageWidth,imageHeight:imageHeight,markers:markers,onChange:this.handleMarkersChange,ref:node=>this._questionMarkers=node}),jsxRuntimeExports.jsx(AnswerChoices,{choices:choices,editingDisabled:editingDisabled,onChange:this.handleChoicesChange}),jsxRuntimeExports.jsx(Behavior,{preferredPopoverDirection:preferredPopoverDirection,multipleAnswers:multipleAnswers,hideChoicesFromInstructions:hideChoicesFromInstructions,onChange:this.handleBehaviorChange})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{const{choices,imageAlt,imageUrl,markers}=this.props;const warnings=[];if(choices.length<2){warnings.push("Question requires at least two answer choices");}if(!imageUrl){warnings.push("Image is not specified for question");}else if(!imageAlt){warnings.push("Question image has no alt text");}if(!markers.length){warnings.push("Question has no markers, to label answers on image");}else {let numNoAnswers=0;let numNoLabels=0;for(const marker of markers){if(!marker.answers.length){numNoAnswers++;}if(!marker.label){numNoLabels++;}}if(numNoAnswers){warnings.push(`Question has ${numNoAnswers} markers with no `+"answers selected");}if(numNoLabels){warnings.push(`Question has ${numNoLabels} markers with no `+"ARIA label");}}return warnings},this.handleImageChange=url=>{this.props.onChange({imageUrl:url,imageWidth:0,imageHeight:0});if(url){Util.getImageSize(url,(width,height)=>{if(this.props.imageUrl===url&&this.props.imageWidth===width&&this.props.imageHeight===height){return}this.props.onChange({imageUrl:url,imageWidth:width,imageHeight:height});});}},this.handleAltChange=alt=>{this.props.onChange({imageAlt:alt});},this.handleChoicesChange=choices=>{this.props.onChange({choices});},this.handleMarkersChange=markers=>{this.props.onChange({markers});},this.handleBehaviorChange=options=>{this.props.onChange(options);};}}LabelImageEditor.defaultProps=labelImageLogic.defaultWidgetOptions;LabelImageEditor.widgetName="label-image";
1836
+ class LabelImageEditor extends React.Component{componentDidUpdate(prevProps){const coordsToMarkers={};prevProps.markers.forEach(marker=>coordsToMarkers[`${marker.x}.${marker.y}`]=marker);const newIndices=this.props.markers.map((marker,index)=>coordsToMarkers.hasOwnProperty(`${marker.x}.${marker.y}`)?-1:index).filter(index=>index!==-1);if(newIndices.length&&this._questionMarkers){this._questionMarkers.openDropdownForMarkerIndices(newIndices);}}serialize(){return EditorJsonify.serialize.call(this)}render(){const{choices,imageAlt,imageUrl,imageWidth,imageHeight,markers,multipleAnswers,hideChoicesFromInstructions,preferredPopoverDirection}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const imageSelected=imageUrl&&imageWidth>0&&imageHeight>0;return jsxRuntimeExports.jsxs("div",{className:styles$7.editor,children:[jsxRuntimeExports.jsx(SelectImage,{onChange:this.handleImageChange,url:imageUrl,editingDisabled:editingDisabled}),imageSelected&&jsxRuntimeExports.jsx(FormWrappedTextField$1,{placeholder:"Alt text (for screen readers)",onChange:e=>this.handleAltChange(e.target.value),value:imageAlt,width:"100%"}),jsxRuntimeExports.jsx(QuestionMarkers,{editingDisabled:editingDisabled,choices:choices,imageUrl:imageSelected?imageUrl:"",imageWidth:imageWidth,imageHeight:imageHeight,markers:markers,onChange:this.handleMarkersChange,ref:node=>this._questionMarkers=node}),jsxRuntimeExports.jsx(AnswerChoices,{choices:choices,editingDisabled:editingDisabled,onChange:this.handleChoicesChange}),jsxRuntimeExports.jsx(Behavior,{preferredPopoverDirection:preferredPopoverDirection,multipleAnswers:multipleAnswers,hideChoicesFromInstructions:hideChoicesFromInstructions,onChange:this.handleBehaviorChange})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{const{choices,imageAlt,imageUrl,markers}=this.props;const warnings=[];if(choices.length<2){warnings.push("Question requires at least two answer choices");}if(!imageUrl){warnings.push("Image is not specified for question");}else if(!imageAlt){warnings.push("Question image has no alt text");}if(!markers.length){warnings.push("Question has no markers, to label answers on image");}else {let numNoAnswers=0;let numNoLabels=0;for(const marker of markers){if(!marker.answers.length){numNoAnswers++;}if(!marker.label){numNoLabels++;}}if(numNoAnswers){warnings.push(`Question has ${numNoAnswers} markers with no `+"answers selected");}if(numNoLabels){warnings.push(`Question has ${numNoLabels} markers with no `+"ARIA label");}}return warnings},this.handleImageChange=url=>{this.props.onChange({imageUrl:url,imageWidth:0,imageHeight:0});if(url){Util.getImageSize(url,(width,height)=>{if(this.props.imageUrl===url&&this.props.imageWidth===width&&this.props.imageHeight===height){return}this.props.onChange({imageUrl:url,imageWidth:width,imageHeight:height});});}},this.handleAltChange=alt=>{this.props.onChange({imageAlt:alt});},this.handleChoicesChange=choices=>{this.props.onChange({choices});},this.handleMarkersChange=markers=>{this.props.onChange({markers});},this.handleBehaviorChange=options=>{this.props.onChange(options);};}}LabelImageEditor.defaultProps=labelImageLogic.defaultWidgetOptions;
1837
1837
 
1838
- class MatcherEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-matcher-editor",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answers here. The preview on the right will show the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix",children:[jsxRuntimeExports.jsx(TextListEditor,{options:this.props.left,onChange:options=>{this.props.onChange({left:options});},layout:"vertical"}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.right,onChange:options=>{this.props.onChange({right:options});},layout:"vertical"})]}),jsxRuntimeExports.jsxs("span",{children:[" ","Labels:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"These are entirely optional."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[0],onChange:e=>{this.onLabelChange(0,e);}}),jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[1],onChange:e=>{this.onLabelChange(1,e);}})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Order of the matched pairs matters:",checked:this.props.orderMatters,onChange:value=>{this.props.onChange({orderMatters:value});}}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:"With this option enabled, only the order provided above will be treated as correct. This is useful when ordering is significant, such as in the context of a proof."}),jsxRuntimeExports.jsx("p",{children:"If disabled, pairwise matching is sufficient. To make this clear, the left column becomes fixed in the provided order and only the cards in the right column can be moved."})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLabelChange=(index,e)=>{const labels=[...this.props.labels];labels[index]=e.target.value;this.props.onChange({labels});},this.getSaveWarnings=()=>{if(this.props.left.length!==this.props.right.length){return ["The two halves of the matcher have different numbers"+" of cards."]}return []},this.serialize=()=>{return {left:this.props.left,right:this.props.right,labels:this.props.labels,orderMatters:this.props.orderMatters,padding:this.props.padding}};}}MatcherEditor.widgetName="matcher";MatcherEditor.defaultProps=matcherLogic.defaultWidgetOptions;
1838
+ class MatcherEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-matcher-editor",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answers here. The preview on the right will show the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix",children:[jsxRuntimeExports.jsx(TextListEditor,{options:this.props.left,onChange:options=>{this.props.onChange({left:options});},layout:"vertical"}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.right,onChange:options=>{this.props.onChange({right:options});},layout:"vertical"})]}),jsxRuntimeExports.jsxs("span",{children:[" ","Labels:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"These are entirely optional."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[0],onChange:e=>{this.onLabelChange(0,e);}}),jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[1],onChange:e=>{this.onLabelChange(1,e);}})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Order of the matched pairs matters:",checked:this.props.orderMatters,onChange:value=>{this.props.onChange({orderMatters:value});}}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:"With this option enabled, only the order provided above will be treated as correct. This is useful when ordering is significant, such as in the context of a proof."}),jsxRuntimeExports.jsx("p",{children:"If disabled, pairwise matching is sufficient. To make this clear, the left column becomes fixed in the provided order and only the cards in the right column can be moved."})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLabelChange=(index,e)=>{const labels=[...this.props.labels];labels[index]=e.target.value;this.props.onChange({labels});},this.getSaveWarnings=()=>{if(this.props.left.length!==this.props.right.length){return ["The two halves of the matcher have different numbers"+" of cards."]}return []},this.serialize=()=>{return {left:this.props.left,right:this.props.right,labels:this.props.labels,orderMatters:this.props.orderMatters,padding:this.props.padding}};}}MatcherEditor.defaultProps=matcherLogic.defaultWidgetOptions;
1839
1839
 
1840
- const{RangeInput: RangeInput$3}=components;const Matrix=MatrixWidget.widget;const MAX_BOARD_SIZE=6;class MatrixEditor extends React.Component{render(){const{matrixBoardSize,prefix,suffix,answers}=this.props;const matrixProps={onBlur:()=>{},onFocus:()=>{},trackInteraction:()=>{},userInput:{answers:answers.map(row=>row.map(cell=>cell==null?"":String(cell)))},handleUserInput:userInput=>{this.change({answers:userInput.answers});},...this.props,options:{matrixBoardSize,prefix,suffix}};return jsxRuntimeExports.jsxs("div",{className:"perseus-matrix-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Max matrix size:"," ",jsxRuntimeExports.jsx(RangeInput$3,{value:this.props.matrixBoardSize,onChange:this.onMatrixBoardSizeChange,useArrowKeys:true})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Matrix,{...matrixProps})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix prefix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"prefix",apiOptions:this.props.apiOptions,content:this.props.prefix,widgetEnabled:false,onChange:newProps=>{this.change({prefix:newProps.content});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix suffix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"suffix",apiOptions:this.props.apiOptions,content:this.props.suffix,widgetEnabled:false,onChange:newProps=>{this.change({suffix:newProps.content});}})]})]})}constructor(...args){super(...args),this.change=(...args)=>{if(this.props.apiOptions.editingDisabled){return}return deprecatedChangeableChange.apply(this,args)},this.onMatrixBoardSizeChange=range=>{const matrixSize=getMatrixSize(this.props.answers);if(range[0]!==null&&range[1]!==null){range=[Math.round(Math.min(Math.max(range[0],1),MAX_BOARD_SIZE)),Math.round(Math.min(Math.max(range[1],1),MAX_BOARD_SIZE))];const answers=_(Math.min(range[0],matrixSize[0])).times(row=>{return _(Math.min(range[1],matrixSize[1])).times(col=>{return this.props.answers[row][col]})});this.props.onChange({matrixBoardSize:range,answers:answers});}},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MatrixEditor.widgetName="matrix";MatrixEditor.defaultProps=matrixLogic.defaultWidgetOptions;
1840
+ const{RangeInput: RangeInput$3}=components;const Matrix=MatrixWidget.widget;const MAX_BOARD_SIZE=6;class MatrixEditor extends React.Component{render(){const{matrixBoardSize,prefix,suffix,answers}=this.props;const matrixProps={onBlur:()=>{},onFocus:()=>{},trackInteraction:()=>{},userInput:{answers:answers.map(row=>row.map(cell=>cell==null?"":String(cell)))},handleUserInput:userInput=>{this.change({answers:userInput.answers});},...this.props,options:{matrixBoardSize,prefix,suffix}};return jsxRuntimeExports.jsxs("div",{className:"perseus-matrix-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Max matrix size:"," ",jsxRuntimeExports.jsx(RangeInput$3,{value:this.props.matrixBoardSize,onChange:this.onMatrixBoardSizeChange,useArrowKeys:true})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Matrix,{...matrixProps})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix prefix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"prefix",apiOptions:this.props.apiOptions,content:this.props.prefix,widgetEnabled:false,onChange:newProps=>{this.change({prefix:newProps.content});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix suffix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"suffix",apiOptions:this.props.apiOptions,content:this.props.suffix,widgetEnabled:false,onChange:newProps=>{this.change({suffix:newProps.content});}})]})]})}constructor(...args){super(...args),this.change=(...args)=>{if(this.props.apiOptions.editingDisabled){return}return deprecatedChangeableChange.apply(this,args)},this.onMatrixBoardSizeChange=range=>{const matrixSize=getMatrixSize(this.props.answers);if(range[0]!==null&&range[1]!==null){range=[Math.round(Math.min(Math.max(range[0],1),MAX_BOARD_SIZE)),Math.round(Math.min(Math.max(range[1],1),MAX_BOARD_SIZE))];const answers=_(Math.min(range[0],matrixSize[0])).times(row=>{return _(Math.min(range[1],matrixSize[1])).times(col=>{return this.props.answers[row][col]})});this.props.onChange({matrixBoardSize:range,answers:answers});}},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MatrixEditor.defaultProps=matrixLogic.defaultWidgetOptions;
1841
1841
 
1842
- const{NumberInput: NumberInput$4,RangeInput: RangeInput$2}=components;const defaultImage={url:null,top:0,left:0};class MeasurerEditor extends React.Component{render(){const image=_.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-measurer",children:[jsxRuntimeExports.jsx("div",{children:"Image displayed under protractor and/or ruler:"}),jsxRuntimeExports.jsxs("div",{children:["URL:"," ",jsxRuntimeExports.jsx("input",{type:"text",className:"perseus-widget-measurer-url",ref:"image-url",defaultValue:image.url,onChange:this._changeUrl}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),image.url&&jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{className:"perseus-widget-left-col",children:["Pixels from top:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:0,onChange:this._changeTop,value:image.top,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("label",{className:"perseus-widget-right-col",children:["Pixels from left:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:0,onChange:this._changeLeft,value:image.left,useArrowKeys:true})]})]}),jsxRuntimeExports.jsxs("div",{children:["Containing area [width, height]:"," ",jsxRuntimeExports.jsx(RangeInput$2,{onChange:this.change("box"),value:this.props.box,useArrowKeys:true})]}),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.props.onChange({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.props.onChange({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:e=>this.change("rulerLabel",e.target.value),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:e=>this.change("rulerTicks",+e.target.value),value:this.props.rulerTicks,children:[1,2,4,8,10,16].map(function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler pixels per unit:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:40,onChange:this.change("rulerPixels"),value:this.props.rulerPixels,useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler length in units:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:10,onChange:this.change("rulerLength"),value:this.props.rulerLength,useArrowKeys:true})]})})]})]})}constructor(...args){super(...args),this.className="perseus-widget-measurer",this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this._changeUrl=e=>{this._changeImage("url",e.target.value);},this._changeTop=newTop=>{this._changeImage("top",newTop);},this._changeLeft=newLeft=>{this._changeImage("left",newLeft);},this._changeImage=(subProp,newValue)=>{const image=_.clone(this.props.image);image[subProp]=newValue;this.change("image",image);},this.renderLabelChoices=choices=>{return choices.map(function(nameAndValue){const[name,value]=nameAndValue;return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MeasurerEditor.widgetName="measurer";MeasurerEditor.defaultProps=measurerLogic.defaultWidgetOptions;
1842
+ const{NumberInput: NumberInput$4,RangeInput: RangeInput$2}=components;const defaultImage={url:null,top:0,left:0};class MeasurerEditor extends React.Component{render(){const image=_.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-measurer",children:[jsxRuntimeExports.jsx("div",{children:"Image displayed under protractor and/or ruler:"}),jsxRuntimeExports.jsxs("div",{children:["URL:"," ",jsxRuntimeExports.jsx("input",{type:"text",className:"perseus-widget-measurer-url",ref:"image-url",defaultValue:image.url,onChange:this._changeUrl}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),image.url&&jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{className:"perseus-widget-left-col",children:["Pixels from top:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:0,onChange:this._changeTop,value:image.top,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("label",{className:"perseus-widget-right-col",children:["Pixels from left:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:0,onChange:this._changeLeft,value:image.left,useArrowKeys:true})]})]}),jsxRuntimeExports.jsxs("div",{children:["Containing area [width, height]:"," ",jsxRuntimeExports.jsx(RangeInput$2,{onChange:this.change("box"),value:this.props.box,useArrowKeys:true})]}),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.props.onChange({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.props.onChange({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:e=>this.change("rulerLabel",e.target.value),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:e=>this.change("rulerTicks",+e.target.value),value:this.props.rulerTicks,children:[1,2,4,8,10,16].map(function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler pixels per unit:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:40,onChange:this.change("rulerPixels"),value:this.props.rulerPixels,useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler length in units:"," ",jsxRuntimeExports.jsx(NumberInput$4,{placeholder:10,onChange:this.change("rulerLength"),value:this.props.rulerLength,useArrowKeys:true})]})})]})]})}constructor(...args){super(...args),this.className="perseus-widget-measurer",this.change=(...args)=>{return deprecatedChangeableChange.apply(this,args)},this._changeUrl=e=>{this._changeImage("url",e.target.value);},this._changeTop=newTop=>{this._changeImage("top",newTop);},this._changeLeft=newLeft=>{this._changeImage("left",newLeft);},this._changeImage=(subProp,newValue)=>{const image=_.clone(this.props.image);image[subProp]=newValue;this.change("image",image);},this.renderLabelChoices=choices=>{return choices.map(function(nameAndValue){const[name,value]=nameAndValue;return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MeasurerEditor.defaultProps=measurerLogic.defaultWidgetOptions;
1843
1843
 
1844
- const{ButtonGroup,NumberInput: NumberInput$3,RangeInput: RangeInput$1}=components;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";class NumberLineEditor extends React.Component{render(){const range=this.props.range;const labelRange=this.props.labelRange;const divisionRange=this.props.divisionRange;range[0]=+range[0];range[1]=+range[1];const width=range[1]-range[0];const numDivisions=this.props.numDivisions;const snapDivisions=this.props.snapDivisions;const tickStep=this.props.tickStep;const isTickCtrl=this.props.isTickCtrl;let step;if(!isTickCtrl){step=tickStep?tickStep/snapDivisions:width/numDivisions/snapDivisions;}else {step=null;}const labelStyleEditorButtons=[{value:"decimal",content:"0.75",title:"Decimals"},{value:"improper",content:"⁷⁄₄",title:"Improper fractions"},{value:"mixed",content:"1¾",title:"Mixed numbers"},{value:"non-reduced",content:"⁸⁄₄",title:"Non-reduced"}];return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-number-line-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Correct x"," ",jsxRuntimeExports.jsxs("select",{value:this.props.correctRel,onChange:this.onChangeRelation,"aria-label":"Select relationship",children:[jsxRuntimeExports.jsx("option",{value:"eq","aria-label":"Equal",children:"="}),jsxRuntimeExports.jsx("option",{value:"lt","aria-label":"Less than",children:"<"}),jsxRuntimeExports.jsx("option",{value:"gt","aria-label":"Greater than",children:">"}),jsxRuntimeExports.jsx("option",{value:"le","aria-label":"Less than or equal",children:"≤"}),jsxRuntimeExports.jsx("option",{value:"ge","aria-label":"Greater than or equal",children:"≥"})]})," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.correctX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"correctX"),checkValidity:val=>val>=range[0]&&val<=range[1]&&(!step||number.isInteger((val-range[0])/step)),placeholder:"answer",size:"normal",useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"This is the correct answer. The answer is validated (as right or wrong) by using only the end position of the point and the relation (=, <, >, ≤, ≥)."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[this.props.static?jsxRuntimeExports.jsx("label",{children:"Range:"}):jsxRuntimeExports.jsxs("label",{children:["Position:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.initialX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"initialX"),placeholder:range[0],checkValidity:val=>{return val>=range[0]&&val<=range[1]},useArrowKeys:true})," ∈ "]}),jsxRuntimeExports.jsx(RangeInput$1,{value:range,onChange:this.onRangeChange,format:this.props.labelStyle,useArrowKeys:true}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsxs("p",{children:["This controls the initial position of the point along the number line and the",jsxRuntimeExports.jsx("strong",{children:"range"}),", the position of the endpoints of the number line. Setting the range constrains the position of the answer and the labels."]}),jsxRuntimeExports.jsx("p",{children:"In static mode, the initial position of the point is determined by Correct x instead of position."})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:["Labels:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:labelRange[0],placeholder:range[0],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,0),useArrowKeys:true}),jsxRuntimeExports.jsx("span",{children:" & "}),jsxRuntimeExports.jsx(NumberInput$3,{value:labelRange[1],placeholder:range[1],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,1),useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the position of the left / right labels. By default, the labels are set by the range ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," Ensure that the labels line up with the tick marks, or it may be confusing for users."]})})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Style:"," ",jsxRuntimeExports.jsx(ButtonGroup,{allowEmpty:false,value:this.props.labelStyle,buttons:labelStyleEditorButtons,onChange:this.onLabelStyleChange}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"This controls the styling of the labels for the two main labels as well as all the tick mark labels, if applicable. Your choices are decimal, improper fractions, mixed fractions, and non-reduced fractions."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[!this.props.static&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tick controller",checked:!!this.props.isTickCtrl,onChange:value=>{this.props.onChange({isTickCtrl:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show label ticks",checked:this.props.labelTicks,onChange:value=>{this.props.onChange({labelTicks:value});}})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:!this.props.static&&jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Start num divisions at"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks. The number of divisions is constrained to"," "+divisionRange[0]+EN_DASH+divisionRange[1],".",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," The user will be able to specify the number of divisions in a number input."]})})]}),!isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Num divisions:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]})," ",jsxRuntimeExports.jsxs("label",{children:["or tick step:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.tickStep||null,format:this.props.labelStyle,onChange:this.onTickStepChange,checkValidity:val=>{return val>0&&val<=width},placeholder:width/this.props.numDivisions,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks; you can either set the number of divisions (2 divisions would split the entire range in two halves), or the tick step (the distance between ticks) and the other value will be updated accordingly."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," There is no check to see if labels coordinate with the tick marks, which may be confusing for users if the blue labels and black ticks are off-step."]})})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{children:["Snap increments per tick:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:snapDivisions,checkValidity:val=>val>0,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"snapDivisions"),useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This determines the number of different places the point will snap between two adjacent tick marks."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"}),"Ensure the required number of snap increments is provided to answer the question."]})})]})]})}constructor(...args){super(...args),this.onRangeChange=range=>{this.props.onChange({range:range});},this.onLabelRangeChange=(i,num)=>{let labelRange=this.props.labelRange.slice();const otherNum=labelRange[1-i];if(num==null||otherNum==null){labelRange[i]=num;}else {labelRange=[Math.min(num,otherNum),Math.max(num,otherNum)];}this.props.onChange({labelRange:labelRange});},this.onDivisionRangeChange=divisionRange=>{let numDivisions=this.props.numDivisions;numDivisions=bound(numDivisions,divisionRange[0],divisionRange[1]);this.props.onChange({divisionRange:divisionRange,numDivisions:numDivisions});},this.onNumChange=(key,value)=>{const opts={};opts[key]=value;this.props.onChange(opts);},this.onNumDivisionsChange=numDivisions=>{const divRange=this.props.divisionRange.slice();numDivisions=_.isFinite(numDivisions)?Math.round(numDivisions):0;numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){numDivisions=Math.min(divRange[1],Math.max(divRange[0],numDivisions));this.props.onChange({tickStep:null,divisionRange:divRange,numDivisions:numDivisions});}},this.onTickStepChange=tickStep=>{this.props.onChange({numDivisions:null,tickStep:tickStep});},this.onChangeRelation=e=>{const value=e.target.value;this.props.onChange({correctRel:value,isInequality:value!=="eq"});},this.onLabelStyleChange=labelStyle=>{this.props.onChange({labelStyle:labelStyle});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}NumberLineEditor.widgetName="number-line";NumberLineEditor.defaultProps=numberLineLogic.defaultWidgetOptions;
1844
+ const{ButtonGroup,NumberInput: NumberInput$3,RangeInput: RangeInput$1}=components;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";class NumberLineEditor extends React.Component{render(){const range=this.props.range;const labelRange=this.props.labelRange;const divisionRange=this.props.divisionRange;range[0]=+range[0];range[1]=+range[1];const width=range[1]-range[0];const numDivisions=this.props.numDivisions;const snapDivisions=this.props.snapDivisions;const tickStep=this.props.tickStep;const isTickCtrl=this.props.isTickCtrl;let step;if(!isTickCtrl){step=tickStep?tickStep/snapDivisions:width/numDivisions/snapDivisions;}else {step=null;}const labelStyleEditorButtons=[{value:"decimal",content:"0.75",title:"Decimals"},{value:"improper",content:"⁷⁄₄",title:"Improper fractions"},{value:"mixed",content:"1¾",title:"Mixed numbers"},{value:"non-reduced",content:"⁸⁄₄",title:"Non-reduced"}];return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-number-line-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Correct x"," ",jsxRuntimeExports.jsxs("select",{value:this.props.correctRel,onChange:this.onChangeRelation,"aria-label":"Select relationship",children:[jsxRuntimeExports.jsx("option",{value:"eq","aria-label":"Equal",children:"="}),jsxRuntimeExports.jsx("option",{value:"lt","aria-label":"Less than",children:"<"}),jsxRuntimeExports.jsx("option",{value:"gt","aria-label":"Greater than",children:">"}),jsxRuntimeExports.jsx("option",{value:"le","aria-label":"Less than or equal",children:"≤"}),jsxRuntimeExports.jsx("option",{value:"ge","aria-label":"Greater than or equal",children:"≥"})]})," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.correctX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"correctX"),checkValidity:val=>val>=range[0]&&val<=range[1]&&(!step||number.isInteger((val-range[0])/step)),placeholder:"answer",size:"normal",useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"This is the correct answer. The answer is validated (as right or wrong) by using only the end position of the point and the relation (=, <, >, ≤, ≥)."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[this.props.static?jsxRuntimeExports.jsx("label",{children:"Range:"}):jsxRuntimeExports.jsxs("label",{children:["Position:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.initialX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"initialX"),placeholder:range[0],checkValidity:val=>{return val>=range[0]&&val<=range[1]},useArrowKeys:true})," ∈ "]}),jsxRuntimeExports.jsx(RangeInput$1,{value:range,onChange:this.onRangeChange,format:this.props.labelStyle,useArrowKeys:true}),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsxs("p",{children:["This controls the initial position of the point along the number line and the",jsxRuntimeExports.jsx("strong",{children:"range"}),", the position of the endpoints of the number line. Setting the range constrains the position of the answer and the labels."]}),jsxRuntimeExports.jsx("p",{children:"In static mode, the initial position of the point is determined by Correct x instead of position."})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:["Labels:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:labelRange[0],placeholder:range[0],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,0),useArrowKeys:true}),jsxRuntimeExports.jsx("span",{children:" & "}),jsxRuntimeExports.jsx(NumberInput$3,{value:labelRange[1],placeholder:range[1],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,1),useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the position of the left / right labels. By default, the labels are set by the range ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," Ensure that the labels line up with the tick marks, or it may be confusing for users."]})})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Style:"," ",jsxRuntimeExports.jsx(ButtonGroup,{allowEmpty:false,value:this.props.labelStyle,buttons:labelStyleEditorButtons,onChange:this.onLabelStyleChange}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"This controls the styling of the labels for the two main labels as well as all the tick mark labels, if applicable. Your choices are decimal, improper fractions, mixed fractions, and non-reduced fractions."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[!this.props.static&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tick controller",checked:!!this.props.isTickCtrl,onChange:value=>{this.props.onChange({isTickCtrl:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show label ticks",checked:this.props.labelTicks,onChange:value=>{this.props.onChange({labelTicks:value});}})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:!this.props.static&&jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Start num divisions at"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks. The number of divisions is constrained to"," "+divisionRange[0]+EN_DASH+divisionRange[1],".",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," The user will be able to specify the number of divisions in a number input."]})})]}),!isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Num divisions:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]})," ",jsxRuntimeExports.jsxs("label",{children:["or tick step:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.tickStep||null,format:this.props.labelStyle,onChange:this.onTickStepChange,checkValidity:val=>{return val>0&&val<=width},placeholder:width/this.props.numDivisions,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks; you can either set the number of divisions (2 divisions would split the entire range in two halves), or the tick step (the distance between ticks) and the other value will be updated accordingly."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," There is no check to see if labels coordinate with the tick marks, which may be confusing for users if the blue labels and black ticks are off-step."]})})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{children:["Snap increments per tick:"," ",jsxRuntimeExports.jsx(NumberInput$3,{value:snapDivisions,checkValidity:val=>val>0,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"snapDivisions"),useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsxs("p",{children:["This determines the number of different places the point will snap between two adjacent tick marks."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"}),"Ensure the required number of snap increments is provided to answer the question."]})})]})]})}constructor(...args){super(...args),this.onRangeChange=range=>{this.props.onChange({range:range});},this.onLabelRangeChange=(i,num)=>{let labelRange=this.props.labelRange.slice();const otherNum=labelRange[1-i];if(num==null||otherNum==null){labelRange[i]=num;}else {labelRange=[Math.min(num,otherNum),Math.max(num,otherNum)];}this.props.onChange({labelRange:labelRange});},this.onDivisionRangeChange=divisionRange=>{let numDivisions=this.props.numDivisions;numDivisions=bound(numDivisions,divisionRange[0],divisionRange[1]);this.props.onChange({divisionRange:divisionRange,numDivisions:numDivisions});},this.onNumChange=(key,value)=>{const opts={};opts[key]=value;this.props.onChange(opts);},this.onNumDivisionsChange=numDivisions=>{const divRange=this.props.divisionRange.slice();numDivisions=_.isFinite(numDivisions)?Math.round(numDivisions):0;numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){numDivisions=Math.min(divRange[1],Math.max(divRange[0],numDivisions));this.props.onChange({tickStep:null,divisionRange:divRange,numDivisions:numDivisions});}},this.onTickStepChange=tickStep=>{this.props.onChange({numDivisions:null,tickStep:tickStep});},this.onChangeRelation=e=>{const value=e.target.value;this.props.onChange({correctRel:value,isInequality:value!=="eq"});},this.onLabelStyleChange=labelStyle=>{this.props.onChange({labelStyle:labelStyle});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}NumberLineEditor.defaultProps=numberLineLogic.defaultWidgetOptions;
1845
1845
 
1846
- const NORMAL="normal";const AUTO="auto";const HORIZONTAL="horizontal";const VERTICAL="vertical";class OrdererEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correctOptions.map(option=>option.content),onChange:options=>{this.onOptionsChange("correctOptions",options);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[" ","Other cards:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Create cards that are not part of the answer."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.otherOptions.map(option=>option.content),onChange:options=>{this.onOptionsChange("otherOptions",options);},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,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Height:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.height,onChange:this.onHeightChange,children:[jsxRuntimeExports.jsx("option",{value:NORMAL,children:"Normal"}),jsxRuntimeExports.jsx("option",{value:AUTO,children:"Automatic"})]})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Use "Normal" for text, "Automatic" for images.'})})]})]})}constructor(...args){super(...args),this.onOptionsChange=(whichOptions,options)=>{const changedCards=options.map(toCard);const correctOptions=whichOptions==="correctOptions"?changedCards:this.props.correctOptions;const otherOptions=whichOptions==="otherOptions"?changedCards:this.props.otherOptions;this.props.onChange({[whichOptions]:changedCards,options:mergeCards(correctOptions,otherOptions)});},this.onLayoutChange=e=>{const layout=e.target.value;switch(layout){case HORIZONTAL:case VERTICAL:this.props.onChange({layout});break;default:throw new Error(`${layout} is not an available layout option`)}},this.onHeightChange=e=>{const height=e.target.value;switch(height){case NORMAL:case AUTO:this.props.onChange({height});break;default:throw new Error(`${height} is not an available height option`)}},this.serialize=()=>{return {options:mergeCards(this.props.correctOptions,this.props.otherOptions),correctOptions:this.props.correctOptions,otherOptions:this.props.otherOptions,height:this.props.height,layout:this.props.layout}};}}OrdererEditor.widgetName="orderer";OrdererEditor.defaultProps=ordererLogic.defaultWidgetOptions;
1846
+ const NORMAL="normal";const AUTO="auto";const HORIZONTAL="horizontal";const VERTICAL="vertical";class OrdererEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correctOptions.map(option=>option.content),onChange:options=>{this.onOptionsChange("correctOptions",options);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[" ","Other cards:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Create cards that are not part of the answer."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.otherOptions.map(option=>option.content),onChange:options=>{this.onOptionsChange("otherOptions",options);},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,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Height:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.height,onChange:this.onHeightChange,children:[jsxRuntimeExports.jsx("option",{value:NORMAL,children:"Normal"}),jsxRuntimeExports.jsx("option",{value:AUTO,children:"Automatic"})]})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Use "Normal" for text, "Automatic" for images.'})})]})]})}constructor(...args){super(...args),this.onOptionsChange=(whichOptions,options)=>{const changedCards=options.map(toCard);const correctOptions=whichOptions==="correctOptions"?changedCards:this.props.correctOptions;const otherOptions=whichOptions==="otherOptions"?changedCards:this.props.otherOptions;this.props.onChange({[whichOptions]:changedCards,options:mergeCards(correctOptions,otherOptions)});},this.onLayoutChange=e=>{const layout=e.target.value;switch(layout){case HORIZONTAL:case VERTICAL:this.props.onChange({layout});break;default:throw new Error(`${layout} is not an available layout option`)}},this.onHeightChange=e=>{const height=e.target.value;switch(height){case NORMAL:case AUTO:this.props.onChange({height});break;default:throw new Error(`${height} is not an available height option`)}},this.serialize=()=>{return {options:mergeCards(this.props.correctOptions,this.props.otherOptions),correctOptions:this.props.correctOptions,otherOptions:this.props.otherOptions,height:this.props.height,layout:this.props.layout}};}}OrdererEditor.defaultProps=ordererLogic.defaultWidgetOptions;
1847
1847
 
1848
- class PhetSimulationEditor extends React.Component{serialize(){return {url:this.props.url,description:this.props.description}}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(LabeledTextField,{label:"URL",value:this.props.url,onChange:url=>this.props.onChange({url}),style:{marginBlockEnd:spacing.large_24}}),jsxRuntimeExports.jsx(LabeledTextField,{label:"Description",value:this.props.description,onChange:description=>this.props.onChange({description})})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{if(makeSafeUrl(this.props.url,"en","https://phet.colorado.edu")===null){return ["Please enter a URL from the PhET domain."]}return []};}}PhetSimulationEditor.defaultProps=phetSimulationLogic.defaultWidgetOptions;PhetSimulationEditor.widgetName="phet-simulation";
1848
+ class PhetSimulationEditor extends React.Component{serialize(){return {url:this.props.url,description:this.props.description}}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(LabeledTextField,{label:"URL",value:this.props.url,onChange:url=>this.props.onChange({url}),style:{marginBlockEnd:spacing.large_24}}),jsxRuntimeExports.jsx(LabeledTextField,{label:"Description",value:this.props.description,onChange:description=>this.props.onChange({description})})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{if(makeSafeUrl(this.props.url,"en","https://phet.colorado.edu")===null){return ["Please enter a URL from the PhET domain."]}return []};}}PhetSimulationEditor.defaultProps=phetSimulationLogic.defaultWidgetOptions;
1849
1849
 
1850
- const{NumberInput: NumberInput$2,RangeInput}=components;const Plotter=PlotterWidget.widget;const STARTING="starting";const CORRECT="correct";const editingStates=[STARTING,CORRECT];function padArray(array,n,value){const copy=_.clone(array);copy.length=n;for(let i=array.length;i<n;i++){copy[i]=value;}return copy}const editorDefaults={scaleY:1,maxY:10,snapsPerLine:2};const formatNumber=num=>"$"+number.round(num,2)+"$";class PlotterEditor extends React.Component{UNSAFE_componentWillMount(){this.fetchPic(this.props.picUrl);}UNSAFE_componentWillReceiveProps(nextProps){this.fetchPic(nextProps.picUrl);if(nextProps.static){this.setState({editing:"starting"});}}render(){const setFromScale=["line","histogram","dotplot"].includes(this.props.type);const canChangeSnaps=!["pic","dotplot"].includes(this.props.type);const plotterProps={options:{type:this.props.type,labels:this.props.labels,categories:this.props.categories,scaleY:this.props.scaleY,maxY:this.props.maxY,snapsPerLine:this.props.snapsPerLine,picUrl:this.props.picUrl,picSize:this.props.picSize,picBoxHeight:this.props.picBoxHeight,plotDimensions:this.props.plotDimensions,labelInterval:this.props.labelInterval,starting:this.props[this.state.editing]},apiOptions:this.props.apiOptions,static:this.props.static,trackInteraction:()=>{},userInput:this.props.correct,handleUserInput:userInput=>{this.props.onChange({correct:userInput});}};return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-plotter-editor",children:[jsxRuntimeExports.jsxs("div",{children:["Chart type:"," ",plotterPlotTypes.map(type=>{return jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",name:"chart-type",checked:this.props.type===type,onChange:_.partial(this.changeType,type)}),type]},type)},this)]}),jsxRuntimeExports.jsxs("div",{children:["Labels:"," ",["x","y"].map((axis,i)=>{return jsxRuntimeExports.jsxs("label",{children:[axis+":",jsxRuntimeExports.jsx("input",{type:"text",onChange:_.partial(this.changeLabel,i),defaultValue:this.props.labels[i]})]},axis)},this)]}),setFromScale&&jsxRuntimeExports.jsxs("div",{className:"set-from-scale-box",children:[jsxRuntimeExports.jsx("span",{className:"categories-title",children:"Set Categories From Scale"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Tick Step:"," ",jsxRuntimeExports.jsx(NumberInput$2,{placeholder:1,useArrowKeys:true,value:this.state.tickStep,onChange:this.handleChangeTickStep})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"The difference between adjacent ticks."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Range:"," ",jsxRuntimeExports.jsx(RangeInput,{placeholder:[0,10],useArrowKeys:true,value:[this.state.minX,this.state.maxX],onChange:this.handleChangeRange})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("button",{onClick:this.setCategoriesFromScale,children:["Set Categories"," "]})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Label Interval:"," ",jsxRuntimeExports.jsx(NumberInput$2,{useArrowKeys:true,value:this.props.labelInterval,onChange:this.changeLabelInterval})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Which ticks to display the labels for. For instance, setting this to "4" will only show every 4th label (plus the last one)'})})]}),this.props.type==="pic"&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Picture:"," ",jsxRuntimeExports.jsx(BlurInput,{className:"pic-url",value:this.props.picUrl??"",onChange:this.changePicUrl}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Use the default picture of Earth, or insert the URL for a different picture using the "Add image" function.'})})]}),this.state.pic&&this.state.pic.width!==this.state.pic.height&&jsxRuntimeExports.jsxs("p",{className:"warning",children:[jsxRuntimeExports.jsx("b",{children:"Warning"}),": You are using a picture which is not square. This means the image will get distorted. You should probably crop it to be square."]})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Categories:"," ",jsxRuntimeExports.jsx(TextListEditor,{ref:"categories",layout:"horizontal",options:this.props.categories,onChange:this.changeCategories})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Scale (y):"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeScale,defaultValue:this.props.scaleY})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Max y:"," ",jsxRuntimeExports.jsx("input",{type:"text",ref:"maxY",onChange:this.changeMax,defaultValue:this.props.maxY})]})}),canChangeSnaps&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Snaps per line:"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeSnaps,defaultValue:this.props.snapsPerLine})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Creates the specified number of divisions between the horizontal lines. Fewer snaps between lines makes the graph easier for the student to create correctly."})})]}),jsxRuntimeExports.jsxs("div",{children:["Editing values:"," ",editingStates.map(editing=>jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",disabled:editing===CORRECT&&this.props.static,checked:this.props.static?editing===STARTING:this.state.editing===editing,onChange:e=>this.changeEditing(editing)}),editing]},editing)),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:"Use this toggle to switch between editing the correct answer (what the student will be graded on) and the starting values (what the student will see plotted when they start the problem). Note: These cannot be the same."}),jsxRuntimeExports.jsx("p",{children:"In static mode, the starting values are rendered out to the displayed widget."})]})]}),jsxRuntimeExports.jsx(Plotter,{...plotterProps})]})}constructor(...args){super(...args),this.state={editing:this.props.static?STARTING:CORRECT,pic:null,loadedUrl:null,minX:null,maxX:null,tickStep:null},this.fetchPic=url=>{if(url==null){if(this.state.pic!==null){this.setState({pic:null,loadedUrl:null});}return}if(this.state.loadedUrl!==url){const pic=new Image;pic.src=url;pic.onload=()=>{this.setState({pic:pic,loadedUrl:url});};}},this.handleChangeTickStep=value=>{this.setState({tickStep:value});},this.handleChangeRange=newValue=>{this.setState({minX:newValue[0],maxX:newValue[1]});},this.changeLabelInterval=value=>{this.props.onChange({labelInterval:value});},this.changeType=type=>{let categories;if(type==="histogram"){categories=[formatNumber(0)].concat(this.props.categories);this.props.onChange({type:type,categories:categories});}else if(this.props.type==="histogram"){categories=this.props.categories.slice(1);this.props.onChange({type:type,categories:categories});}else {this.props.onChange({type:type});}if(categories){const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");}},this.changeLabel=(i,e)=>{const labels=_.clone(this.props.labels);labels[i]=e.target.value;this.props.onChange({labels:labels});},this.changePicUrl=value=>{const url=Util.getRealImageUrl(value);this.props.onChange({picUrl:url});},this.changeCategories=categories=>{let n=categories.length;if(this.props.type==="histogram"){n--;}const value=this.props.scaleY;this.props.onChange({categories:categories,correct:padArray(this.props.correct,n,value),starting:padArray(this.props.starting,n,value)});},this.changeScale=e=>{const oldScale=this.props.scaleY;const newScale=+e.target.value||editorDefaults.scaleY;const scale=function(value){return value*newScale/oldScale};const maxY=scale(this.props.maxY);this.props.onChange({scaleY:newScale,maxY:maxY,correct:this.props.correct.map(scale),starting:this.props.starting.map(scale)});ReactDOM.findDOMNode(this.refs.maxY).value=maxY;},this.changeMax=e=>{this.props.onChange({maxY:+e.target.value||editorDefaults.maxY});},this.changeSnaps=e=>{this.props.onChange({snapsPerLine:+e.target.value||editorDefaults.snapsPerLine});},this.changeEditing=editing=>{this.setState({editing:editing});},this.setCategoriesFromScale=()=>{const scale=this.state.tickStep||1;const min=this.state.minX||0;const max=this.state.maxX||0;const length=Math.floor((max-min)/scale)*scale;let categories;if(this.props.type==="histogram"||this.props.type==="dotplot"){categories=_.range(0,length+scale,scale);}else {categories=_.range(scale,length+scale,scale);}categories=categories.map(num=>num+min);categories=categories.map(formatNumber);this.changeCategories(categories);const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");},this.serialize=()=>{const json=_.pick(this.props,"correct","starting","type","labels","categories","scaleY","maxY","snapsPerLine","labelInterval");if(this.props.type==="pic"){json.picUrl=this.props.picUrl;}return json};}}PlotterEditor.widgetName="plotter";PlotterEditor.defaultProps=plotterLogic.defaultWidgetOptions;
1850
+ const{NumberInput: NumberInput$2,RangeInput}=components;const Plotter=PlotterWidget.widget;const STARTING="starting";const CORRECT="correct";const editingStates=[STARTING,CORRECT];function padArray(array,n,value){const copy=_.clone(array);copy.length=n;for(let i=array.length;i<n;i++){copy[i]=value;}return copy}const editorDefaults={scaleY:1,maxY:10,snapsPerLine:2};const formatNumber=num=>"$"+number.round(num,2)+"$";class PlotterEditor extends React.Component{UNSAFE_componentWillMount(){this.fetchPic(this.props.picUrl);}UNSAFE_componentWillReceiveProps(nextProps){this.fetchPic(nextProps.picUrl);if(nextProps.static){this.setState({editing:"starting"});}}render(){const setFromScale=["line","histogram","dotplot"].includes(this.props.type);const canChangeSnaps=!["pic","dotplot"].includes(this.props.type);const plotterProps={options:{type:this.props.type,labels:this.props.labels,categories:this.props.categories,scaleY:this.props.scaleY,maxY:this.props.maxY,snapsPerLine:this.props.snapsPerLine,picUrl:this.props.picUrl,picSize:this.props.picSize,picBoxHeight:this.props.picBoxHeight,plotDimensions:this.props.plotDimensions,labelInterval:this.props.labelInterval,starting:this.props[this.state.editing]},apiOptions:this.props.apiOptions,static:this.props.static,trackInteraction:()=>{},userInput:this.props.correct,handleUserInput:userInput=>{this.props.onChange({correct:userInput});}};return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-plotter-editor",children:[jsxRuntimeExports.jsxs("div",{children:["Chart type:"," ",plotterPlotTypes.map(type=>{return jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",name:"chart-type",checked:this.props.type===type,onChange:_.partial(this.changeType,type)}),type]},type)},this)]}),jsxRuntimeExports.jsxs("div",{children:["Labels:"," ",["x","y"].map((axis,i)=>{return jsxRuntimeExports.jsxs("label",{children:[axis+":",jsxRuntimeExports.jsx("input",{type:"text",onChange:_.partial(this.changeLabel,i),defaultValue:this.props.labels[i]})]},axis)},this)]}),setFromScale&&jsxRuntimeExports.jsxs("div",{className:"set-from-scale-box",children:[jsxRuntimeExports.jsx("span",{className:"categories-title",children:"Set Categories From Scale"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Tick Step:"," ",jsxRuntimeExports.jsx(NumberInput$2,{placeholder:1,useArrowKeys:true,value:this.state.tickStep,onChange:this.handleChangeTickStep})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"The difference between adjacent ticks."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Range:"," ",jsxRuntimeExports.jsx(RangeInput,{placeholder:[0,10],useArrowKeys:true,value:[this.state.minX,this.state.maxX],onChange:this.handleChangeRange})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("button",{onClick:this.setCategoriesFromScale,children:["Set Categories"," "]})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Label Interval:"," ",jsxRuntimeExports.jsx(NumberInput$2,{useArrowKeys:true,value:this.props.labelInterval,onChange:this.changeLabelInterval})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Which ticks to display the labels for. For instance, setting this to "4" will only show every 4th label (plus the last one)'})})]}),this.props.type==="pic"&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Picture:"," ",jsxRuntimeExports.jsx(BlurInput,{className:"pic-url",value:this.props.picUrl??"",onChange:this.changePicUrl}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:'Use the default picture of Earth, or insert the URL for a different picture using the "Add image" function.'})})]}),this.state.pic&&this.state.pic.width!==this.state.pic.height&&jsxRuntimeExports.jsxs("p",{className:"warning",children:[jsxRuntimeExports.jsx("b",{children:"Warning"}),": You are using a picture which is not square. This means the image will get distorted. You should probably crop it to be square."]})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Categories:"," ",jsxRuntimeExports.jsx(TextListEditor,{ref:"categories",layout:"horizontal",options:this.props.categories,onChange:this.changeCategories})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Scale (y):"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeScale,defaultValue:this.props.scaleY})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Max y:"," ",jsxRuntimeExports.jsx("input",{type:"text",ref:"maxY",onChange:this.changeMax,defaultValue:this.props.maxY})]})}),canChangeSnaps&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Snaps per line:"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeSnaps,defaultValue:this.props.snapsPerLine})]}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Creates the specified number of divisions between the horizontal lines. Fewer snaps between lines makes the graph easier for the student to create correctly."})})]}),jsxRuntimeExports.jsxs("div",{children:["Editing values:"," ",editingStates.map(editing=>jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",disabled:editing===CORRECT&&this.props.static,checked:this.props.static?editing===STARTING:this.state.editing===editing,onChange:e=>this.changeEditing(editing)}),editing]},editing)),jsxRuntimeExports.jsxs(InfoTip,{children:[jsxRuntimeExports.jsx("p",{children:"Use this toggle to switch between editing the correct answer (what the student will be graded on) and the starting values (what the student will see plotted when they start the problem). Note: These cannot be the same."}),jsxRuntimeExports.jsx("p",{children:"In static mode, the starting values are rendered out to the displayed widget."})]})]}),jsxRuntimeExports.jsx(Plotter,{...plotterProps})]})}constructor(...args){super(...args),this.state={editing:this.props.static?STARTING:CORRECT,pic:null,loadedUrl:null,minX:null,maxX:null,tickStep:null},this.fetchPic=url=>{if(url==null){if(this.state.pic!==null){this.setState({pic:null,loadedUrl:null});}return}if(this.state.loadedUrl!==url){const pic=new Image;pic.src=url;pic.onload=()=>{this.setState({pic:pic,loadedUrl:url});};}},this.handleChangeTickStep=value=>{this.setState({tickStep:value});},this.handleChangeRange=newValue=>{this.setState({minX:newValue[0],maxX:newValue[1]});},this.changeLabelInterval=value=>{this.props.onChange({labelInterval:value});},this.changeType=type=>{let categories;if(type==="histogram"){categories=[formatNumber(0)].concat(this.props.categories);this.props.onChange({type:type,categories:categories});}else if(this.props.type==="histogram"){categories=this.props.categories.slice(1);this.props.onChange({type:type,categories:categories});}else {this.props.onChange({type:type});}if(categories){const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");}},this.changeLabel=(i,e)=>{const labels=_.clone(this.props.labels);labels[i]=e.target.value;this.props.onChange({labels:labels});},this.changePicUrl=value=>{const url=Util.getRealImageUrl(value);this.props.onChange({picUrl:url});},this.changeCategories=categories=>{let n=categories.length;if(this.props.type==="histogram"){n--;}const value=this.props.scaleY;this.props.onChange({categories:categories,correct:padArray(this.props.correct,n,value),starting:padArray(this.props.starting,n,value)});},this.changeScale=e=>{const oldScale=this.props.scaleY;const newScale=+e.target.value||editorDefaults.scaleY;const scale=function(value){return value*newScale/oldScale};const maxY=scale(this.props.maxY);this.props.onChange({scaleY:newScale,maxY:maxY,correct:this.props.correct.map(scale),starting:this.props.starting.map(scale)});ReactDOM.findDOMNode(this.refs.maxY).value=maxY;},this.changeMax=e=>{this.props.onChange({maxY:+e.target.value||editorDefaults.maxY});},this.changeSnaps=e=>{this.props.onChange({snapsPerLine:+e.target.value||editorDefaults.snapsPerLine});},this.changeEditing=editing=>{this.setState({editing:editing});},this.setCategoriesFromScale=()=>{const scale=this.state.tickStep||1;const min=this.state.minX||0;const max=this.state.maxX||0;const length=Math.floor((max-min)/scale)*scale;let categories;if(this.props.type==="histogram"||this.props.type==="dotplot"){categories=_.range(0,length+scale,scale);}else {categories=_.range(scale,length+scale,scale);}categories=categories.map(num=>num+min);categories=categories.map(formatNumber);this.changeCategories(categories);const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");},this.serialize=()=>{const json=_.pick(this.props,"correct","starting","type","labels","categories","scaleY","maxY","snapsPerLine","labelInterval");if(this.props.type==="pic"){json.picUrl=this.props.picUrl;}return json};}}PlotterEditor.defaultProps=plotterLogic.defaultWidgetOptions;
1851
1851
 
1852
- 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 deprecatedChangeableChange.apply(this,args)},this.getSaveWarnings=()=>{return validateOptions(this.props.height,this.props.programID)};}}PythonProgramEditor.widgetName="python-program";PythonProgramEditor.defaultProps=pythonProgramLogic.defaultWidgetOptions;
1852
+ 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 deprecatedChangeableChange.apply(this,args)},this.getSaveWarnings=()=>{return validateOptions(this.props.height,this.props.programID)};}}PythonProgramEditor.defaultProps=pythonProgramLogic.defaultWidgetOptions;
1853
1853
 
1854
1854
  var styles$2 = {"tile":"perseus_H66MpddK","statusRow":"perseus_WkPB-jwX","radioOptionActionsContainer":"perseus_5aWP3vgw","buttonRow":"perseus_ezHjicvY"};
1855
1855
 
@@ -1868,7 +1868,7 @@ const boxStyle={width:sizing.size_560,justifyContent:"center",boxSizing:"border-
1868
1868
 
1869
1869
  const RadioOptionSettings=React.forwardRef(function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove,editingDisabled},ref){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;const contentEditorRef=React.useRef(null);React.useImperativeHandle(ref,()=>({focus:()=>{contentEditorRef.current?.focus();}}));return jsxRuntimeExports.jsxs("div",{className:styles$2.tile,children:[jsxRuntimeExports.jsx("fieldset",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:styles$2.statusRow,children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect}),jsxRuntimeExports.jsx(BodyText,{size:"small",weight:"bold",tag:"span",children:"Status"}),jsxRuntimeExports.jsx(SegmentedControl,{"aria-label":"Choice status",selectedValue:correct?"correct":"incorrect",onChange:value=>{onStatusChange(index,value==="correct");},options:[{value:"correct",label:"Correct"},{value:"incorrect",label:"Incorrect"}],disabled:editingDisabled})]})}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{ref:contentEditorRef,content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange,editingDisabled:editingDisabled}),jsxRuntimeExports.jsx(BodyText,{size:"small",weight:"bold",tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(TextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);},autoResize:true,disabled:editingDisabled}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement),editingDisabled:editingDisabled})]})});
1870
1870
 
1871
- class RadioEditor extends React.Component{componentDidMount(){if(this.props.multipleSelect&&this.props.countChoices){this.props.onChange({numCorrect:deriveNumCorrect(this.props.choices)});}const needsIdUpdate=this.props.choices.some(choice=>!choice.id||choice.id.trim()==="");if(needsIdUpdate){const updatedChoices=this.props.choices.map((choice,index)=>({...choice,id:this.ensureValidIds(choice.id,index)}));this.props.onChange({choices:updatedChoices});}}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);const isEditingDisabled=this.props.apiOptions.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,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,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(BodyText,{size:"xsmall",tag:"span",children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{ref:this.getChoiceRef(choice.id),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,editingDisabled:isEditingDisabled},`choice-${choice.id}`)),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"},disabled:isEditingDisabled,children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),disabled:isEditingDisabled,children:"None of the above"})]})]})}constructor(...args){super(...args),this.choiceRefs=new Map,this.getChoiceRef=choiceId=>{if(!this.choiceRefs.has(choiceId)){this.choiceRefs.set(choiceId,React.createRef());}return this.choiceRefs.get(choiceId)},this.onMultipleSelectChange=options=>{const isMultipleSelect=options.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=options=>{const countChoices=options.countChoices;this.props.onChange({countChoices});},this.generateChoiceId=index=>{return `radio-choice-${index}`},this.ensureValidIds=(choiceId,index)=>{if(!choiceId||choiceId.trim()===""){return this.generateChoiceId(index)}return choiceId},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content,id:this.ensureValidIds(choice.id,i)}});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];this.choiceRefs.delete(deleted.id);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.getChoiceRef(newChoice.id).current?.focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{const firstChoice=this.props.choices[0];if(firstChoice?.id){this.getChoiceRef(firstChoice.id).current?.focus();}return true},this.getSaveWarnings=()=>{if(!this.props.choices.some(choice=>choice.correct)){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.bestPractices={url:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",label:"Multiple choice best practices"};RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1871
+ class RadioEditor extends React.Component{componentDidMount(){if(this.props.multipleSelect&&this.props.countChoices){this.props.onChange({numCorrect:deriveNumCorrect(this.props.choices)});}const needsIdUpdate=this.props.choices.some(choice=>!choice.id||choice.id.trim()==="");if(needsIdUpdate){const updatedChoices=this.props.choices.map((choice,index)=>({...choice,id:this.ensureValidIds(choice.id,index)}));this.props.onChange({choices:updatedChoices});}}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);const isEditingDisabled=this.props.apiOptions.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,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,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(BodyText,{size:"xsmall",tag:"span",children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{ref:this.getChoiceRef(choice.id),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,editingDisabled:isEditingDisabled},`choice-${choice.id}`)),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"},disabled:isEditingDisabled,children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),disabled:isEditingDisabled,children:"None of the above"})]})]})}constructor(...args){super(...args),this.choiceRefs=new Map,this.getChoiceRef=choiceId=>{if(!this.choiceRefs.has(choiceId)){this.choiceRefs.set(choiceId,React.createRef());}return this.choiceRefs.get(choiceId)},this.onMultipleSelectChange=options=>{const isMultipleSelect=options.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=options=>{const countChoices=options.countChoices;this.props.onChange({countChoices});},this.generateChoiceId=index=>{return `radio-choice-${index}`},this.ensureValidIds=(choiceId,index)=>{if(!choiceId||choiceId.trim()===""){return this.generateChoiceId(index)}return choiceId},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content,id:this.ensureValidIds(choice.id,i)}});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];this.choiceRefs.delete(deleted.id);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.getChoiceRef(newChoice.id).current?.focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{const firstChoice=this.props.choices[0];if(firstChoice?.id){this.getChoiceRef(firstChoice.id).current?.focus();}return true},this.getSaveWarnings=()=>{if(!this.props.choices.some(choice=>choice.correct)){return ["No choice is marked as correct."]}return []};}}RadioEditor.bestPractices={url:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",label:"Multiple choice best practices"};RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1872
1872
 
1873
1873
  var styles$1 = {"card":"perseus_j1ydPJka"};
1874
1874
 
@@ -1876,15 +1876,15 @@ const cardInputStyle={flexGrow:1};function CardEditor({index,value,isFirst,isLas
1876
1876
 
1877
1877
  var styles = {"editor":"perseus_nJ-Uq5eT","section":"perseus_vTiphIsj","cards":"perseus_xhRr18kA","addCard":"perseus_cwHzt54c"};
1878
1878
 
1879
- const maxCards=10;const minCards=2;const defaultOptions=sorterLogic.defaultWidgetOptions;const layoutOptions={horizontal:"Horizontal",vertical:"Vertical"};const SorterEditor=React.forwardRef(function SorterEditor({correct=defaultOptions.correct,layout=defaultOptions.layout,padding=defaultOptions.padding,onChange},ref){React.useImperativeHandle(ref,()=>({serialize:()=>{return {correct,layout,padding}},getSaveWarnings:()=>{const warnings=[];if(correct.length<minCards){warnings.push(`Sorter requires at least ${minCards} cards.`);}if(correct.some(card=>card.trim()==="")){warnings.push("Sorter cards cannot be blank.");}return warnings}}),[correct,layout,padding]);const onCardChange=(index,value)=>{const newCorrect=[...correct];newCorrect[index]=value;onChange({correct:newCorrect});};const onAddCard=()=>{if(correct.length>=maxCards){return}onChange({correct:[...correct,""]});};const onMoveCard=(index,offset)=>{const newCorrect=[...correct];const newIndex=index+offset;[newCorrect[index],newCorrect[newIndex]]=[newCorrect[newIndex],newCorrect[index]];onChange({correct:newCorrect});};const onDeleteCard=index=>{onChange({correct:correct.filter((card,i)=>i!==index)});};return jsxRuntimeExports.jsxs(View,{className:styles.editor,children:[jsxRuntimeExports.jsxs(View,{className:styles.section,children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsxs(InfoTip,{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("p",{children:"For horizontal orientation, the top input represents the leftmost card and the bottom input represents the rightmost card."})]})]}),jsxRuntimeExports.jsx(View,{tag:"ol",className:styles.cards,children:correct.map((card,i)=>jsxRuntimeExports.jsx(CardEditor,{index:i,value:card,isFirst:i===0,isLast:i===correct.length-1,onChange:value=>onCardChange(i,value),onMoveUp:()=>onMoveCard(i,-1),onMoveDown:()=>onMoveCard(i,1),onDelete:()=>onDeleteCard(i)},i))}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,className:styles.addCard,disabled:correct.length>=maxCards,onClick:onAddCard,children:"Add a card"})]}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Layout",field:jsxRuntimeExports.jsx(TypedSingleSelect,{options:layoutOptions,selectedValue:layout,onChange:newLayout=>onChange({layout:newLayout})})}),jsxRuntimeExports.jsx(InfoTip,{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:padding,onChange:value=>{onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})});var SorterEditor$1 = Object.assign(SorterEditor,{widgetName:"sorter",defaultProps:defaultOptions});
1879
+ const maxCards=10;const minCards=2;const defaultOptions=sorterLogic.defaultWidgetOptions;const layoutOptions={horizontal:"Horizontal",vertical:"Vertical"};const SorterEditor=React.forwardRef(function SorterEditor({correct=defaultOptions.correct,layout=defaultOptions.layout,padding=defaultOptions.padding,onChange},ref){React.useImperativeHandle(ref,()=>({serialize:()=>{return {correct,layout,padding}},getSaveWarnings:()=>{const warnings=[];if(correct.length<minCards){warnings.push(`Sorter requires at least ${minCards} cards.`);}if(correct.some(card=>card.trim()==="")){warnings.push("Sorter cards cannot be blank.");}return warnings}}),[correct,layout,padding]);const onCardChange=(index,value)=>{const newCorrect=[...correct];newCorrect[index]=value;onChange({correct:newCorrect});};const onAddCard=()=>{if(correct.length>=maxCards){return}onChange({correct:[...correct,""]});};const onMoveCard=(index,offset)=>{const newCorrect=[...correct];const newIndex=index+offset;[newCorrect[index],newCorrect[newIndex]]=[newCorrect[newIndex],newCorrect[index]];onChange({correct:newCorrect});};const onDeleteCard=index=>{onChange({correct:correct.filter((card,i)=>i!==index)});};return jsxRuntimeExports.jsxs(View,{className:styles.editor,children:[jsxRuntimeExports.jsxs(View,{className:styles.section,children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsxs(InfoTip,{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("p",{children:"For horizontal orientation, the top input represents the leftmost card and the bottom input represents the rightmost card."})]})]}),jsxRuntimeExports.jsx(View,{tag:"ol",className:styles.cards,children:correct.map((card,i)=>jsxRuntimeExports.jsx(CardEditor,{index:i,value:card,isFirst:i===0,isLast:i===correct.length-1,onChange:value=>onCardChange(i,value),onMoveUp:()=>onMoveCard(i,-1),onMoveDown:()=>onMoveCard(i,1),onDelete:()=>onDeleteCard(i)},i))}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,className:styles.addCard,disabled:correct.length>=maxCards,onClick:onAddCard,children:"Add a card"})]}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Layout",field:jsxRuntimeExports.jsx(TypedSingleSelect,{options:layoutOptions,selectedValue:layout,onChange:newLayout=>onChange({layout:newLayout})})}),jsxRuntimeExports.jsx(InfoTip,{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:padding,onChange:value=>{onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})});var SorterEditor$1 = Object.assign(SorterEditor,{defaultProps:defaultOptions});
1880
1880
 
1881
- const{NumberInput}=components;const Table=TableWidget.widget;class TableEditor extends React.Component{render(){const tableProps={options:{headers:this.props.headers,rows:this.props.rows,columns:this.props.columns,answers:this.props.answers},onChange:this.props.onChange,userInput:this.props.answers,handleUserInput:userInput=>{if(this.props.apiOptions?.editingDisabled){return}this.props.onChange({answers:userInput});},apiOptions:this.props.apiOptions,editableHeaders:true,onFocus:()=>{},onBlur:()=>{},trackInteraction:()=>{},Editor:Editor};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of columns:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:this.numberOfColumns,value:this.props.columns,onChange:val=>{if(val){this.onSizeInput(this.props.rows,val);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of rows:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:"numberOfRows",value:this.props.rows,onChange:val=>{if(val){this.onSizeInput(val,this.props.columns);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsxs("div",{children:[" ","Table of answers:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(Table,{...tableProps})})]})}constructor(...args){super(...args),this.numberOfColumns=React.createRef(),this.focus=()=>{this.numberOfColumns.current?.focus();},this.onSizeInput=(numRawRows,numRawColumns)=>{let rows=+numRawRows||0;let columns=+numRawColumns||0;rows=Math.min(Math.max(1,rows),30);columns=Math.min(Math.max(1,columns),6);const oldColumns=this.props.columns;const oldRows=this.props.rows;const answers=this.props.answers;if(rows<=oldRows){answers.length=rows;}else {_(rows-oldRows).times(function(){answers.push(Util.stringArrayOfSize(oldColumns));});}function fixColumnSizing(array){if(columns<=oldColumns){array.length=columns;}else {_(columns-oldColumns).times(function(){array.push("");});}}const headers=this.props.headers;fixColumnSizing(headers);_.each(answers,fixColumnSizing);this.props.onChange({rows:rows,columns:columns,answers:answers,headers:headers});},this.serialize=()=>{const json=_.pick(this.props,"headers","rows","columns");return _.extend({},json,{answers:this.props.answers.map(_.clone)})};}}TableEditor.propTypes={rows:PropTypes.number,columns:PropTypes.number,headers:PropTypes.arrayOf(PropTypes.string),answers:PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))};TableEditor.widgetName="table";TableEditor.defaultProps=tableLogic.defaultWidgetOptions;
1881
+ const{NumberInput}=components;const Table=TableWidget.widget;class TableEditor extends React.Component{render(){const tableProps={options:{headers:this.props.headers,rows:this.props.rows,columns:this.props.columns,answers:this.props.answers},onChange:this.props.onChange,userInput:this.props.answers,handleUserInput:userInput=>{if(this.props.apiOptions?.editingDisabled){return}this.props.onChange({answers:userInput});},apiOptions:this.props.apiOptions,editableHeaders:true,onFocus:()=>{},onBlur:()=>{},trackInteraction:()=>{},Editor:Editor};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of columns:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:this.numberOfColumns,value:this.props.columns,onChange:val=>{if(val){this.onSizeInput(this.props.rows,val);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of rows:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:"numberOfRows",value:this.props.rows,onChange:val=>{if(val){this.onSizeInput(val,this.props.columns);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsxs("div",{children:[" ","Table of answers:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(Table,{...tableProps})})]})}constructor(...args){super(...args),this.numberOfColumns=React.createRef(),this.focus=()=>{this.numberOfColumns.current?.focus();},this.onSizeInput=(numRawRows,numRawColumns)=>{let rows=+numRawRows||0;let columns=+numRawColumns||0;rows=Math.min(Math.max(1,rows),30);columns=Math.min(Math.max(1,columns),6);const oldColumns=this.props.columns;const oldRows=this.props.rows;const answers=this.props.answers;if(rows<=oldRows){answers.length=rows;}else {_(rows-oldRows).times(function(){answers.push(Util.stringArrayOfSize(oldColumns));});}function fixColumnSizing(array){if(columns<=oldColumns){array.length=columns;}else {_(columns-oldColumns).times(function(){array.push("");});}}const headers=this.props.headers;fixColumnSizing(headers);_.each(answers,fixColumnSizing);this.props.onChange({rows:rows,columns:columns,answers:answers,headers:headers});},this.serialize=()=>{const json=_.pick(this.props,"headers","rows","columns");return _.extend({},json,{answers:this.props.answers.map(_.clone)})};}}TableEditor.propTypes={rows:PropTypes.number,columns:PropTypes.number,headers:PropTypes.arrayOf(PropTypes.string),answers:PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))};TableEditor.defaultProps=tableLogic.defaultWidgetOptions;
1882
1882
 
1883
1883
  const KA_VIDEO_URL=/khanacademy\.org\/.*\/v\/(.*)$/;function getSlugFromUrl(url){const match=KA_VIDEO_URL.exec(url);if(match){return match[1]}return url}function VideoSettings(props){const[inputValue,setInputValue]=React.useState(props.location);function handleUrlChange(url){props.onChange({location:getSlugFromUrl(url)});}return jsxRuntimeExports.jsx(LabeledField,{label:"KA Video Slug",description:"KA video URLs will be converted to just the slug.",field:jsxRuntimeExports.jsx(TextArea,{value:inputValue,onChange:setInputValue,onBlur:e=>handleUrlChange(e.target.value),autoResize:true})})}
1884
1884
 
1885
- class VideoEditor extends React.Component{render(){return jsxRuntimeExports.jsx(VideoSettings,{...this.props})}constructor(...args){super(...args),this.serialize=()=>{return {location:this.props.location}};}}VideoEditor.widgetName="video";VideoEditor.defaultProps=videoLogic.defaultWidgetOptions;
1885
+ class VideoEditor extends React.Component{render(){return jsxRuntimeExports.jsx(VideoSettings,{...this.props})}constructor(...args){super(...args),this.serialize=()=>{return {location:this.props.location}};}}VideoEditor.defaultProps=videoLogic.defaultWidgetOptions;
1886
1886
 
1887
- var AllEditors = [CategorizerEditor,CSProgramEditor,DefinitionEditor,DropdownEditor,ExplanationEditor,ExpressionEditor,FreeResponseEditor,GradedGroupEditor,GradedGroupSetEditor,GrapherEditor,GroupEditor,IframeEditor,ImageEditor,InputNumberEditor,InteractionEditor,InteractiveGraphEditor,LabelImageEditor,MatcherEditor,MatrixEditor,MeasurerEditor,NumberLineEditor,NumericInputEditor,OrdererEditor,PhetSimulationEditor,PlotterEditor,PythonProgramEditor,SorterEditor$1,TableEditor,VideoEditor,RadioEditor,DeprecatedStandinEditor];
1887
+ var AllEditors = {categorizer:CategorizerEditor,"cs-program":CSProgramEditor,definition:DefinitionEditor,"deprecated-standin":DeprecatedStandinEditor,dropdown:DropdownEditor,explanation:ExplanationEditor,expression:ExpressionEditor,"free-response":FreeResponseEditor,"graded-group":GradedGroupEditor,"graded-group-set":GradedGroupSetEditor,grapher:GrapherEditor,group:GroupEditor,iframe:IframeEditor,image:ImageEditor,"input-number":InputNumberEditor,interaction:InteractionEditor,"interactive-graph":InteractiveGraphEditor,"label-image":LabelImageEditor,matcher:MatcherEditor,matrix:MatrixEditor,measurer:MeasurerEditor,"number-line":NumberLineEditor,"numeric-input":NumericInputEditor,orderer:OrdererEditor,"phet-simulation":PhetSimulationEditor,plotter:PlotterEditor,"python-program":PythonProgramEditor,radio:RadioEditor,sorter:SorterEditor$1,table:TableEditor,video:VideoEditor};
1888
1888
 
1889
1889
  Widgets.registerEditors(AllEditors);Widgets.registerWidgets(widgets);Widgets.replaceDeprecatedWidgets();Widgets.replaceDeprecatedEditors();
1890
1890