@khanacademy/perseus-editor 28.10.1 → 28.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ var xIcon__default = /*#__PURE__*/_interopDefaultCompat(xIcon);
132
132
  var checkIcon__default = /*#__PURE__*/_interopDefaultCompat(checkIcon);
133
133
  var minusCircleIcon__default = /*#__PURE__*/_interopDefaultCompat(minusCircleIcon);
134
134
 
135
- const libName="@khanacademy/perseus-editor";const libVersion="28.10.1";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
135
+ const libName="@khanacademy/perseus-editor";const libVersion="28.10.2";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
136
136
 
137
137
  var jsxRuntime = {exports: {}};
138
138
 
@@ -1805,8 +1805,8 @@ function RadioImageEditor({initialImageUrl,initialImageAltText,initialImageWidth
1805
1805
 
1806
1806
  function getMovedChoices(choices,hasNoneOfTheAbove,choiceIndex,movement){const newChoices=[...choices];const[removedChoice]=newChoices.splice(choiceIndex,1);switch(movement){case "top":if(choiceIndex===0){return choices}newChoices.unshift(removedChoice);break;case "up":if(choiceIndex===0){return choices}newChoices.splice(choiceIndex-1,0,removedChoice);break;case "down":if(choiceIndex===choices.length-1){return choices}if(choiceIndex===choices.length-2&&hasNoneOfTheAbove){return choices}newChoices.splice(choiceIndex+1,0,removedChoice);break;case "bottom":if(choiceIndex===choices.length-1){return choices}if(hasNoneOfTheAbove){const removedNoneOfTheAbove=newChoices.pop();newChoices.push(removedChoice);if(removedNoneOfTheAbove){newChoices.push(removedNoneOfTheAbove);}}else {newChoices.push(removedChoice);}break}return newChoices}function setImageProxyFromMarkdownContent(markdownContent){const images=[];const parsedMarkdown=perseus.PerseusMarkdown.parse(markdownContent,{});perseus.PerseusMarkdown.traverseContent(parsedMarkdown,node=>{if(node.type==="image"){images.push({url:node.target||"",altText:node.alt||""});}});let proxiedContent=markdownContent;images.forEach((image,index)=>{const originalPattern=`![${image.altText}](${image.url})`;const replacement=`![Image ${index+1}]`;const patternIndex=proxiedContent.indexOf(originalPattern);if(patternIndex!==-1){proxiedContent=proxiedContent.substring(0,patternIndex)+replacement+proxiedContent.substring(patternIndex+originalPattern.length);}});return [proxiedContent,images]}function setMarkdownContentFromImageProxy(proxiedContent,images){let markdownContent=proxiedContent;for(let i=0;i<images.length;i++){const image=images[i];markdownContent=markdownContent.replace(`![Image ${i+1}]`,`![${image.altText}](${image.url})`);}return markdownContent}
1807
1807
 
1808
- const RadioOptionContentAndImageEditor=props=>{const{content,choiceIndex,onContentChange,isNoneOfTheAbove}=props;const uniqueId=React__namespace.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const[proxiedContent,setProxiedContent]=React__namespace.useState("");const[images,setImages]=React__namespace.useState([]);const[addingImage,setAddingImage]=React__namespace.useState(false);React__namespace.useEffect(()=>{const[proxiedContent,parsedImages]=setImageProxyFromMarkdownContent(content??"");setProxiedContent(proxiedContent);setImages(parsedImages);async function fetchAllDimensions(){const imagesWithDimensions=await Promise.all(parsedImages.map(async image=>{try{const size=await perseus.Util.getImageSizeModern(image.url);return {...image,width:size[0],height:size[1]}}catch(error){return image}}));setImages(imagesWithDimensions);}void fetchAllDimensions();},[content]);const handleAddImage=(choiceIndex,imageUrl,imageAltText,width,height)=>{const newContent=`${content}
1809
- ![${imageAltText}](${imageUrl})`;onContentChange(choiceIndex,newContent);};const handleDeleteImage=imageIndex=>{const substr=`![Image ${imageIndex+1}]`;const newProxiedContent=proxiedContent.replace(substr,"");setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handleUpdateImage=(imageIndex,url,altText,width,height)=>{const newImages=[...images];newImages[imageIndex]={url,altText,width,height};setImages(newImages);const newContent=setMarkdownContentFromImageProxy(proxiedContent,newImages);onContentChange(choiceIndex,newContent);};const handleContentChange=(choiceIndex,newProxiedContent)=>{setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handlePaste=e=>{const imageURL=e.clipboardData.getData("text");if(imageURL.includes("cdn.kastatic.org")||imageURL.includes("graphie")){e.preventDefault();handleAddImage(choiceIndex,imageURL,"");}};const handleDeleteImageConfirmation=imageIndex=>{if(window.confirm("Are you sure you want to delete this image?")){handleDeleteImage(imageIndex);}};if(isNoneOfTheAbove){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:contentTextAreaId,value:"None of the above",disabled:true,onChange:()=>{},autoResize:true})]})}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,style:{marginBlockEnd:wonderBlocksTokens.sizing.size_040},children:"Content"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:contentTextAreaId,value:proxiedContent,placeholder:"Type a choice here...",onChange:value=>{handleContentChange(choiceIndex,value);},onPaste:handlePaste,autoResize:true}),!addingImage&&jsxRuntimeExports.jsx(Button__default.default,{startIcon:plusIcon__default.default,size:"small",kind:"tertiary",style:{alignSelf:"flex-start"},onClick:()=>{setAddingImage(true);},children:"Add image"}),addingImage&&jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:"",initialImageAltText:"",containerClassName:styles.imageEditorContainer,onSave:(imageUrl,imageAltText,width,height)=>{handleAddImage(choiceIndex,imageUrl,imageAltText);},onClose:()=>{setAddingImage(false);}}),images?.map((image,imageIndex)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:`Image ${imageIndex+1}`,expanded:true,containerStyle:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,marginBlockStart:wonderBlocksTokens.sizing.size_040,marginBlockEnd:wonderBlocksTokens.sizing.size_040},panelStyle:{paddingBlockEnd:wonderBlocksTokens.sizing.size_120},children:[jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:"Preview",field:jsxRuntimeExports.jsx(ImagePreview,{src:image.url,alt:`Preview: ${image.altText??"No alt text"}`,width:image.width,height:image.height})}),jsxRuntimeExports.jsx("div",{style:{marginTop:wonderBlocksTokens.sizing.size_160},children:jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:image.url,initialImageAltText:image.altText,initialImageWidth:image.width,initialImageHeight:image.height,onSave:(imageUrl,imageAltText,width,height)=>{handleUpdateImage(imageIndex,imageUrl,imageAltText,width,height);},onDelete:()=>{handleDeleteImageConfirmation(imageIndex);}})})]},image.url))??null]})};
1808
+ const RadioOptionContentAndImageEditor=React__namespace.forwardRef(function RadioOptionContentAndImageEditor(props,ref){const{content,choiceIndex,onContentChange,isNoneOfTheAbove}=props;const uniqueId=React__namespace.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const textAreaRef=React__namespace.useRef(null);React__namespace.useImperativeHandle(ref,()=>({focus:()=>{textAreaRef.current?.focus();}}));const[proxiedContent,setProxiedContent]=React__namespace.useState("");const[images,setImages]=React__namespace.useState([]);const[addingImage,setAddingImage]=React__namespace.useState(false);React__namespace.useEffect(()=>{const[proxiedContent,parsedImages]=setImageProxyFromMarkdownContent(content??"");setProxiedContent(proxiedContent);setImages(parsedImages);async function fetchAllDimensions(){const imagesWithDimensions=await Promise.all(parsedImages.map(async image=>{try{const size=await perseus.Util.getImageSizeModern(image.url);return {...image,width:size[0],height:size[1]}}catch(error){return image}}));setImages(imagesWithDimensions);}void fetchAllDimensions();},[content]);const handleAddImage=(choiceIndex,imageUrl,imageAltText,width,height)=>{const newContent=`${content}
1809
+ ![${imageAltText}](${imageUrl})`;onContentChange(choiceIndex,newContent);};const handleDeleteImage=imageIndex=>{const substr=`![Image ${imageIndex+1}]`;const newProxiedContent=proxiedContent.replace(substr,"");setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handleUpdateImage=(imageIndex,url,altText,width,height)=>{const newImages=[...images];newImages[imageIndex]={url,altText,width,height};setImages(newImages);const newContent=setMarkdownContentFromImageProxy(proxiedContent,newImages);onContentChange(choiceIndex,newContent);};const handleContentChange=(choiceIndex,newProxiedContent)=>{setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handlePaste=e=>{const imageURL=e.clipboardData.getData("text");if(imageURL.includes("cdn.kastatic.org")||imageURL.includes("graphie")){e.preventDefault();handleAddImage(choiceIndex,imageURL,"");}};const handleDeleteImageConfirmation=imageIndex=>{if(window.confirm("Are you sure you want to delete this image?")){handleDeleteImage(imageIndex);}};if(isNoneOfTheAbove){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:contentTextAreaId,value:"None of the above",disabled:true,onChange:()=>{},autoResize:true})]})}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,style:{marginBlockEnd:wonderBlocksTokens.sizing.size_040},children:"Content"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:contentTextAreaId,ref:textAreaRef,value:proxiedContent,placeholder:"Type a choice here...",onChange:value=>{handleContentChange(choiceIndex,value);},onPaste:handlePaste,autoResize:true}),!addingImage&&jsxRuntimeExports.jsx(Button__default.default,{startIcon:plusIcon__default.default,size:"small",kind:"tertiary",style:{alignSelf:"flex-start"},onClick:()=>{setAddingImage(true);},children:"Add image"}),addingImage&&jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:"",initialImageAltText:"",containerClassName:styles.imageEditorContainer,onSave:(imageUrl,imageAltText,width,height)=>{handleAddImage(choiceIndex,imageUrl,imageAltText);},onClose:()=>{setAddingImage(false);}}),images?.map((image,imageIndex)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:`Image ${imageIndex+1}`,expanded:true,containerStyle:{backgroundColor:wonderBlocksTokens.semanticColor.core.background.base.default,marginBlockStart:wonderBlocksTokens.sizing.size_040,marginBlockEnd:wonderBlocksTokens.sizing.size_040},panelStyle:{paddingBlockEnd:wonderBlocksTokens.sizing.size_120},children:[jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:"Preview",field:jsxRuntimeExports.jsx(ImagePreview,{src:image.url,alt:`Preview: ${image.altText??"No alt text"}`,width:image.width,height:image.height})}),jsxRuntimeExports.jsx("div",{style:{marginTop:wonderBlocksTokens.sizing.size_160},children:jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:image.url,initialImageAltText:image.altText,initialImageWidth:image.width,initialImageHeight:image.height,onSave:(imageUrl,imageAltText,width,height)=>{handleUpdateImage(imageIndex,imageUrl,imageAltText,width,height);},onDelete:()=>{handleDeleteImageConfirmation(imageIndex);}})})]},image.url))??null]})});
1810
1810
 
1811
1811
  function RadioOptionSettingsActions({content,showDelete,showMove,onDelete,onMove}){return jsxRuntimeExports.jsxs("div",{className:styles.radioOptionActionsContainer,children:[showDelete&&jsxRuntimeExports.jsx(Button__default.default,{size:"small",kind:"tertiary",startIcon:trashIcon__default.default,onClick:()=>{if(window.confirm(`Are you sure you want to remove this choice?
1812
1812
 
@@ -1814,9 +1814,9 @@ ${content}`)){onDelete();}},children:"Remove"}),showMove&&jsxRuntimeExports.jsxs
1814
1814
 
1815
1815
  function RadioStatusPill({index,correct,multipleSelect,onClick}){return jsxRuntimeExports.jsx(Pill__default.default,{size:"large",style:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,color:correct?wonderBlocksTokens.color.white:wonderBlocksTokens.color.red,backgroundColor:correct?wonderBlocksTokens.color.activeGreen:wonderBlocksTokens.color.fadedRed8,borderRadius:multipleSelect?wonderBlocksTokens.border.radius.radius_040:wonderBlocksTokens.sizing.size_240,border:`1px solid ${correct?wonderBlocksTokens.color.activeGreen:wonderBlocksTokens.color.red}`,width:wonderBlocksTokens.sizing.size_560,flexDirection:"row"},onClick:onClick,children:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{size:"small",icon:correct?checkIcon__default.default:minusCircleIcon__default.default,style:{marginInlineEnd:wonderBlocksTokens.sizing.size_060},color:correct?wonderBlocksTokens.color.white:wonderBlocksTokens.color.red}),String.fromCharCode(65+index)]})})}
1816
1816
 
1817
- function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove}){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React__namespace.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{style:{display:"inline",marginInlineEnd:wonderBlocksTokens.sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill__default.default,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,outlineColor:correct?wonderBlocksTokens.semanticColor.core.background.instructive.default:wonderBlocksTokens.semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill__default.default,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,outlineColor:!correct?wonderBlocksTokens.semanticColor.core.background.instructive.default:wonderBlocksTokens.semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange}),jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:wonderBlocksTokens.sizing.size_040,marginBlockEnd:wonderBlocksTokens.sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);},autoResize:true}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})}
1817
+ const RadioOptionSettings=React__namespace.forwardRef(function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove},ref){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React__namespace.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;const contentEditorRef=React__namespace.useRef(null);React__namespace.useImperativeHandle(ref,()=>({focus:()=>{contentEditorRef.current?.focus();}}));return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{style:{display:"inline",marginInlineEnd:wonderBlocksTokens.sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill__default.default,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,outlineColor:correct?wonderBlocksTokens.semanticColor.core.background.instructive.default:wonderBlocksTokens.semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill__default.default,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:wonderBlocksTokens.sizing.size_080,outlineColor:!correct?wonderBlocksTokens.semanticColor.core.background.instructive.default:wonderBlocksTokens.semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{ref:contentEditorRef,content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange}),jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:wonderBlocksTokens.sizing.size_040,marginBlockEnd:wonderBlocksTokens.sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);},autoResize:true}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})});
1818
1818
 
1819
- class RadioEditor extends React__namespace.Component{componentDidMount(){if(this.props.multipleSelect&&this.props.countChoices){this.props.onChange({numCorrect:perseusCore.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:perseusCore.deriveNumCorrect(choices)}}render(){const numCorrect=perseusCore.deriveNumCorrect(this.props.choices);const isEditingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link__default.default,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Specify number correct",checked:this.props.countChoices,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),jsxRuntimeExports.jsxs(wonderBlocksTypography.Footnote,{children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{index:index,choice:choice,multipleSelect:this.props.multipleSelect,onStatusChange:this.onStatusChange,onContentChange:this.onContentChange,onRationaleChange:this.onRationaleChange,showDelete:this.props.choices.length>=2,showMove:this.props.choices.length>1&&!choice.isNoneOfTheAbove,onDelete:()=>this.onDelete(index),onMove:this.handleMove},`choice-${choice.id}}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button__default.default,{size:"small",kind:"tertiary",startIcon:plusIcon__default.default,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button__default.default,{size:"small",kind:"tertiary",startIcon:plusIcon__default.default,onClick:this.addChoice.bind(this,true),children:"None of the above"})]})]})}constructor(...args){super(...args),this.onMultipleSelectChange=options=>{const isMultipleSelect=options.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=perseusCore.deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:perseusCore.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:perseusCore.deriveNumCorrect(choices)});},this.onStatusChange=(choiceIndex,correct)=>{let newCheckedList;if(correct&&!this.props.multipleSelect){newCheckedList=this.props.choices.map(_=>false);}else {newCheckedList=this.props.choices.map(c=>c.correct);}newCheckedList[choiceIndex]=correct;this.onChange({checked:newCheckedList});},this.onContentChange=(choiceIndex,newContent)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],content:newContent};this.props.onChange({choices:choices});},this.onRationaleChange=(choiceIndex,newRationale)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],rationale:newRationale};if(newRationale===""){delete choices[choiceIndex].rationale;}this.props.onChange({choices:choices});},this.onDelete=choiceIndex=>{const choices=this.props.choices.slice();const deleted=choices[choiceIndex];choices.splice(choiceIndex,1);this.props.onChange({choices,hasNoneOfTheAbove:this.props.hasNoneOfTheAbove&&!deleted.isNoneOfTheAbove,numCorrect:perseusCore.deriveNumCorrect(choices)});},this.addChoice=(noneOfTheAbove,e)=>{e.preventDefault();const choices=this.props.choices.slice();const newChoice={isNoneOfTheAbove:noneOfTheAbove,content:"",id:crypto.randomUUID()};const addIndex=choices.length-(this.props.hasNoneOfTheAbove?1:0);choices.splice(addIndex,0,newChoice);this.props.onChange({choices:choices,hasNoneOfTheAbove:noneOfTheAbove||this.props.hasNoneOfTheAbove},()=>{this.refs[`choice-editor${addIndex}`].refs["content-editor"].focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{this.refs["choice-editor0"].refs["content-editor"].focus();return true},this.getSaveWarnings=()=>{if(!___default.default.some(___default.default.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=perseusCore.radioLogic.defaultWidgetOptions;
1819
+ class RadioEditor extends React__namespace.Component{componentDidMount(){if(this.props.multipleSelect&&this.props.countChoices){this.props.onChange({numCorrect:perseusCore.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:perseusCore.deriveNumCorrect(choices)}}render(){const numCorrect=perseusCore.deriveNumCorrect(this.props.choices);const isEditingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link__default.default,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Specify number correct",checked:this.props.countChoices,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:wonderBlocksTokens.sizing.size_060}}),jsxRuntimeExports.jsxs(wonderBlocksTypography.Footnote,{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},`choice-${choice.id}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button__default.default,{size:"small",kind:"tertiary",startIcon:plusIcon__default.default,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button__default.default,{size:"small",kind:"tertiary",startIcon:plusIcon__default.default,onClick:this.addChoice.bind(this,true),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__namespace.createRef());}return this.choiceRefs.get(choiceId)},this.onMultipleSelectChange=options=>{const isMultipleSelect=options.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=perseusCore.deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:perseusCore.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:perseusCore.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:perseusCore.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(!___default.default.some(___default.default.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=perseusCore.radioLogic.defaultWidgetOptions;
1820
1820
 
1821
1821
  const{InfoTip: InfoTip$1,TextListEditor}=perseus.components;const HORIZONTAL="horizontal";const VERTICAL="vertical";class SorterEditor extends React__namespace.Component{render(){const editor=this;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answer (in the correct order) here. The preview on the right will have the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correct,onChange:function(options,cb){editor.props.onChange({correct:options},cb);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$1,{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(wonderBlocksForm.Checkbox,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.serialize=()=>{return ___default.default.pick(this.props,"correct","layout","padding")};}}SorterEditor.propTypes={correct:PropTypes__default.default.array,layout:PropTypes__default.default.oneOf([HORIZONTAL,VERTICAL]),padding:PropTypes__default.default.bool};SorterEditor.widgetName="sorter";SorterEditor.defaultProps=perseusCore.sorterLogic.defaultWidgetOptions;
1822
1822