@khanacademy/perseus-editor 34.1.1 → 34.1.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/es/index.css +2 -2
- package/dist/es/index.css.map +1 -1
- package/dist/es/index.js +7 -7
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/testing/feature-flags-util.d.ts +0 -2
- package/dist/widgets/interactive-graph-editor/interactive-graph-editor.d.ts +18 -18
- package/package.json +7 -7
package/dist/es/index.js
CHANGED
|
@@ -63,7 +63,7 @@ import minusCircle from '@phosphor-icons/core/regular/minus-circle.svg';
|
|
|
63
63
|
import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
|
|
64
64
|
import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
|
|
65
65
|
|
|
66
|
-
const libName="@khanacademy/perseus-editor";const libVersion="34.1.
|
|
66
|
+
const libName="@khanacademy/perseus-editor";const libVersion="34.1.2";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
67
67
|
|
|
68
68
|
var jsxRuntime = {exports: {}};
|
|
69
69
|
|
|
@@ -1411,7 +1411,7 @@ var jsxRuntimeExports = requireJsxRuntime();
|
|
|
1411
1411
|
|
|
1412
1412
|
const devices={PHONE:"phone",TABLET:"tablet",DESKTOP:"desktop"};const lintGutterWidth=36;const perseusFrameBorderWidth=1;
|
|
1413
1413
|
|
|
1414
|
-
const SCREEN_SIZES={phone:{width:320,height:480,framedWidth:320},tablet:{width:750,height:920,framedWidth:525},desktop:{width:688,height:600,framedWidth:688}};const DeviceFramer=({children,deviceType="phone",nochrome})=>{const scale=React.useMemo(()=>SCREEN_SIZES[deviceType].framedWidth/SCREEN_SIZES[deviceType].width,[deviceType]);const withChromeStyle=React.useMemo(()=>({backgroundColor:"white",
|
|
1414
|
+
const SCREEN_SIZES={phone:{width:320,height:480,framedWidth:320},tablet:{width:750,height:920,framedWidth:525},desktop:{width:688,height:600,framedWidth:688}};const DeviceFramer=({children,deviceType="phone",nochrome})=>{const scale=React.useMemo(()=>SCREEN_SIZES[deviceType].framedWidth/SCREEN_SIZES[deviceType].width,[deviceType]);const withChromeStyle=React.useMemo(()=>({backgroundColor:"white",color:"black",textAlign:"left",width:SCREEN_SIZES[deviceType].width,height:SCREEN_SIZES[deviceType].height,border:"solid 1px #CCC",margin:8,zoom:scale}),[deviceType,scale]);if(nochrome){return jsxRuntimeExports.jsx("div",{style:{width:SCREEN_SIZES[deviceType].framedWidth+2*perseusFrameBorderWidth+lintGutterWidth},children:jsxRuntimeExports.jsx("div",{children:children})},"screen")}return jsxRuntimeExports.jsx("div",{className:"screen",style:{...withChromeStyle,textAlign:"start"},children:children},"screen")};
|
|
1415
1415
|
|
|
1416
1416
|
const IMAGE_MARKDOWN_REGEX=/!\[[^\]]*\]\([^)]+\)/g;function getFirstAvailableWidgetIndex(widgetType,widgets){const widgetNames=Object.keys(widgets);for(let i=1;i<=widgetNames.length+1;i++){if(!widgetNames.includes(`${widgetType} ${i}`)){return i}}return 1}async function convertImageMarkdownToImageWidget(question,onEditorChange){const{content,widgets}=question;const newWidgets={...widgets};const matches=Array.from(content.matchAll(IMAGE_MARKDOWN_REGEX));if(matches.length===0){return}const replacements=[];for(const match of matches){const imageIndex=getFirstAvailableWidgetIndex("image",newWidgets);const imageNode=PerseusMarkdown.parse(match[0],{});const imageUrl=imageNode[0].content[0].target;const imageAlt=imageNode[0].content[0].alt;const imageSize=await Util.getImageSizeModern(imageUrl);const[width,height]=imageSize;newWidgets[`image ${imageIndex}`]=generateImageWidget({options:generateImageOptions({backgroundImage:{url:imageUrl,width,height},alt:imageAlt})});replacements.push({original:match[0],replacement:`[[☃ image ${imageIndex}]]`});}let newContent=content;for(const{original,replacement}of replacements){newContent=newContent.replace(original,replacement);}onEditorChange({content:newContent,widgets:newWidgets});}function getCtaForIssueId(issueId,question,onEditorChange){switch(issueId){case "image-markdown":return {label:"Convert all image markdown to widget",onClick:()=>convertImageMarkdownToImageWidget(question,onEditorChange)};default:return null}}
|
|
1417
1417
|
|
|
@@ -1463,7 +1463,7 @@ katex.__defineMacro("\\ce",function(context){return chemParse(context.consumeArg
|
|
|
1463
1463
|
|
|
1464
1464
|
function detectTexErrors(content){const errors=[];const ast=PerseusMarkdown.parse(content,{});PerseusMarkdown.traverseContent(ast,node=>{if(node.type==="math"||node.type==="blockMath"){const texContent=preprocessTex(node.content);try{katex.renderToString(texContent,{colorIsTextColor:true});}catch(e){errors.push({math:texContent,message:e.message});}}});return errors}
|
|
1465
1465
|
|
|
1466
|
-
const{HUD: HUD$1}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updateIssues();this._updatePreviewFrames();}componentDidUpdate(prevProps){if(prevProps.json!==this.props.json){this._updateIssues();}this._updatePreviewFrames();}_updateIssues(){const sections=this.props.json instanceof Array?this.props.json:[this.props.json];const issues=sections.map(section=>{const parsed=PerseusMarkdown.parse(section.content??"",{});const linterContext={content:section.content,widgets:section.widgets,stack:[]};const sectionIssues=PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[];const texErrors=detectTexErrors(section.content??"");const texIssues=texErrors.map((error,index)=>WARNINGS.texError(error.math,error.message,index));return [...texIssues,...sectionIssues]});this.setState({issues});}_updatePreviewFrames(){if(this.props.mode==="preview"){this.refs["frame-all"].sendNewData({type:"article-all",data:this._sections().map((section,i)=>{return this._apiOptionsForSection(section,i)})});}else if(this.props.mode==="edit"){this._sections().forEach((section,i)=>{this.refs["frame-"+i].sendNewData({type:"article",data:this._apiOptionsForSection(section,i)});});}}_apiOptionsForSection(section,sectionIndex){const editor=this.refs[`editor${sectionIndex}`];return {apiOptions:{...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true},json:section,linterContext:{contentType:"article",highlightLint:this.state.highlightLint},legacyPerseusLint:editor?editor.getSaveWarnings():[]}}_sections(){const json=this.props.json;return json instanceof Array?json:[json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.
|
|
1466
|
+
const{HUD: HUD$1}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updateIssues();this._updatePreviewFrames();}componentDidUpdate(prevProps){if(prevProps.json!==this.props.json){this._updateIssues();}this._updatePreviewFrames();}_updateIssues(){const sections=this.props.json instanceof Array?this.props.json:[this.props.json];const issues=sections.map(section=>{const parsed=PerseusMarkdown.parse(section.content??"",{});const linterContext={content:section.content,widgets:section.widgets,stack:[]};const sectionIssues=PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[];const texErrors=detectTexErrors(section.content??"");const texIssues=texErrors.map((error,index)=>WARNINGS.texError(error.math,error.message,index));return [...texIssues,...sectionIssues]});this.setState({issues});}_updatePreviewFrames(){if(this.props.mode==="preview"){this.refs["frame-all"].sendNewData({type:"article-all",data:this._sections().map((section,i)=>{return this._apiOptionsForSection(section,i)})});}else if(this.props.mode==="edit"){this._sections().forEach((section,i)=>{this.refs["frame-"+i].sendNewData({type:"article",data:this._apiOptionsForSection(section,i)});});}}_apiOptionsForSection(section,sectionIndex){const editor=this.refs[`editor${sectionIndex}`];return {apiOptions:{...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true},json:section,linterContext:{contentType:"article",highlightLint:this.state.highlightLint},legacyPerseusLint:editor?editor.getSaveWarnings():[]}}_sections(){const json=this.props.json;return json instanceof Array?json:[json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("fieldset",{disabled:editingDisabled,children:[jsxRuntimeExports.jsx(IssuesPanel,{issues:this.state.issues[i]}),jsxRuntimeExports.jsxs("div",{className:"pod-title",children:["Section ",i+1,jsxRuntimeExports.jsxs("div",{style:{display:"inline-block",float:"right"},children:[sectionImageUploadGenerator(i),jsxRuntimeExports.jsx(SectionControlButton,{icon:plusIcon,disabled:editingDisabled,onClick:()=>{this._handleAddSectionAfter(i);},title:"Add a new section after this one"}),i+1<sections.length&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleDownIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionLater(i);},title:"Move this section down"}),i>0&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleUpIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionEarlier(i);},title:"Move this section up"}),jsxRuntimeExports.jsx(SectionControlButton,{icon:trashIcon,disabled:editingDisabled,onClick:()=>{const msg="Are you sure you "+"want to delete section "+(i+1)+"?";if(confirm(msg)){this._handleRemoveSection(i);}},title:"Delete this section"})]})]}),jsxRuntimeExports.jsx(Editor,{...section,apiOptions:apiOptions,imageUploader:imageUploader,onChange:newProps=>this._handleEditorChange(i,newProps),placeholder:"Type your section text here...",ref:"editor"+i})]})}),jsxRuntimeExports.jsx("div",{className:"editor-preview",children:this._renderIframePreview(i,true)})]},i)]}),this._renderAddSection(editingDisabled),this._renderLinterHUD()]})}_renderAddSection(editingDisabled){return jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,disabled:editingDisabled,kind:"tertiary","aria-label":"Add a section",onClick:()=>{this._handleAddSectionAfter(this._sections().length-1);},children:"Add a section"})})})}_renderLinterHUD(){return jsxRuntimeExports.jsx(HUD$1,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})}_renderIframePreview(i,nochrome){const isMobile=this.props.screen==="phone"||this.props.screen==="tablet";return jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.screen,nochrome:nochrome,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:"frame-"+i,datasetKey:"mobile",datasetValue:isMobile,seamless:nochrome,url:this.props.previewURL},this.props.screen)})}_renderPreviewMode(){return jsxRuntimeExports.jsx("div",{className:"standalone-preview",children:this._renderIframePreview("all",false)})}_handleMoveSectionEarlier(i){if(i===0){return}const sections=[...this._sections()];const section=sections[i];sections.splice(i,1);sections.splice(i-1,0,section);this.props.onChange({json:sections});}_handleMoveSectionLater(i){const sections=[...this._sections()];if(i+1===sections.length){return}const section=sections[i];sections.splice(i,1);sections.splice(i+1,0,section);this.props.onChange({json:sections});}_handleAddSectionAfter(i){const sections=_.clone(this.serialize());const newSection=i>=0?{widgets:sections[i].widgets}:{};sections.splice(i+1,0,newSection);this.props.onChange({json:sections});}_handleRemoveSection(i){const sections=[...this._sections()];sections.splice(i,1);this.props.onChange({json:sections});}serialize(){if(this.props.mode==="edit"){return this._sections().map((section,i)=>{return this.refs["editor"+i].serialize()})}if(this.props.mode==="preview"||this.props.mode==="json"){return this.props.json}throw new PerseusError("Could not serialize; mode "+this.props.mode+" not found",Errors.Internal)}getSaveWarnings(){if(this.props.mode!=="edit"){throw new PerseusError("Can only get save warnings in edit mode.",Errors.NotAllowed)}return this._sections().map((section,i)=>{return this.refs["editor"+i].getSaveWarnings()})}render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{className:"framework-perseus perseus-article-editor",children:[this.props.mode==="edit"&&this._renderEditor(),this.props.mode==="preview"&&this._renderPreviewMode(),this.props.mode==="json"&&jsxRuntimeExports.jsxs("div",{className:"json-editor",children:[jsxRuntimeExports.jsx("div",{className:"json-editor-warning",children:jsxRuntimeExports.jsx("span",{children:"Warning: Editing in this mode can lead to broken articles!"})}),jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,onChange:this._handleJsonChange,value:this.props.json,parser:parseAndMigratePerseusArticle,editingDisabled:editingDisabled})]})]})})}constructor(...args){super(...args),this.state={highlightLint:true,issues:[]},this._handleJsonChange=newJson=>{this.props.onChange({json:newJson});},this._handleEditorChange=(i,newProps)=>{const sections=[...this._sections()];sections[i]={...sections[i],...newProps};this.props.onChange({json:sections});};}}ArticleEditor.defaultProps={json:[{}],mode:"edit",screen:"desktop",sectionImageUploadGenerator:()=>jsxRuntimeExports.jsx("span",{})};
|
|
1467
1467
|
|
|
1468
1468
|
const iconChevronRight={path:"M62.808 49.728q0 3.36-2.352 5.88l-41.72 41.664q-2.352 2.408-5.768 2.408t-5.768-2.408l-4.872-4.76q-2.352-2.52-2.352-5.88t2.352-5.712l31.08-31.136-31.08-31.024q-2.352-2.52-2.352-5.88t2.352-5.712l4.872-4.76q2.296-2.408 5.768-2.408t5.768 2.408l41.72 41.664q2.352 2.296 2.352 5.656z",width:63.034,height:100};const iconCircleArrowDown={path:"M50.046 83.676q1.767 0 2.907-1.14l29.526-29.526q1.197-1.197 1.197-2.907t-1.197-2.964l-5.928-5.928q-1.197-1.14-2.964-1.14t-2.907 1.14l-12.312 12.312l0-32.661q0-1.71-1.254-2.964t-2.907-1.254l-8.322 0q-1.71 0-2.964 1.254t-1.254 2.964l0 32.661l-12.312-12.312q-1.197-1.254-2.907-1.254t-2.907 1.254l-5.928 5.928q-1.197 1.197-1.197 2.964t1.197 2.907l29.469 29.526q1.197 1.14 2.964 1.14zm49.989-33.63q.057 13.623-6.669 25.137t-18.24 18.183-25.08 6.669-25.137-6.726q-11.514-6.726-18.183-18.183-6.726-11.571-6.726-25.137t6.726-25.08 18.24-18.24 25.08-6.669q13.566 0 25.08 6.726 11.514 6.669 18.24 18.183t6.669 25.137z",width:100,height:100};const iconCircleArrowUp={path:"M54.207 83.391q1.653 0 2.907-1.254t1.254-2.907l0-32.718l12.312 12.312q1.254 1.254 2.964 1.254t2.907-1.254l5.928-5.928q1.197-1.197 1.14-2.964 0-1.767-1.14-2.907l-29.526-29.526q-1.197-1.14-2.907-1.14t-2.964 1.14l-29.469 29.526q-1.197 1.254-1.197 2.964t1.197 2.907l5.928 5.928q1.197 1.197 2.907 1.197t2.907-1.197l12.312-12.312l0 32.718q0 1.653 1.254 2.907t2.964 1.254l8.322 0zm45.828-33.345q.057 13.623-6.669 25.137t-18.24 18.183-25.08 6.669-25.137-6.726q-11.514-6.726-18.183-18.183-6.726-11.571-6.726-25.137t6.726-25.08 18.24-18.24 25.08-6.669q13.566 0 25.08 6.726 11.514 6.669 18.24 18.183t6.669 25.137z",width:100,height:100};const iconDesktop={path:"M94.208 52.119l0-43.746q0-.69-.506-1.15t-1.196-.506l-84.088 0q-.69 0-1.196.506t-.506 1.15l0 43.746q0 .69.506 1.196t1.196.506l84.088 0q.69 0 1.196-.506t.506-1.196zm6.716-43.746l0 57.224q0 3.45-2.484 5.934t-5.934 2.484l-28.566 0q0 3.128 2.53 7.774.828 1.61.828 2.622t-1.012 2.07q-1.012 1.012-2.346.966l-26.91 0q-1.38 0-2.392-1.012t-1.012-2.024q0-1.058 1.656-4.14t1.748-6.256l-28.612 0q-3.45 0-5.934-2.484t-2.484-5.934l0-57.224q0-3.45 2.484-5.934t5.934-2.438l84.088 0q3.45 0 5.98 2.438 2.438 2.484 2.438 5.934z",width:100,height:86.648};const iconMobilePhone={path:"M36.04 89.557q0-2.584-1.836-4.42t-4.42-1.836-4.352 1.836q-1.836 1.836-1.836 4.42t1.836 4.352 4.42 1.836q2.652-.068 4.42-1.836t1.768-4.352zm16.184-12.444l0-54.74q0-1.088-.748-1.768t-1.768-.68l-39.78 0q-1.088 0-1.768.748t-.68 1.7l0 54.74q0 1.02.748 1.768t1.7.68l39.78 0q1.02-.068 1.768-.748t.748-1.7zm-14.892-65.892q0-1.224-1.292-1.292l-12.444 0q-1.224.068-1.224 1.292t1.224 1.224l12.444 0q1.292 0 1.292-1.224zm22.372-1.292l0 79.628q0 3.944-2.992 6.936t-7.004 2.992l-39.78 0q-4.012 0-7.004-2.924-2.924-2.924-2.924-7.004l0-79.628q0-4.012 2.924-6.936t7.004-2.992l39.78 0q4.012-.068 7.004 2.924t2.992 7.004z",width:60.013,height:100};const iconPlus={path:"M99.758 43.09l0 13.578q0 2.852-1.984 4.836t-4.836 1.984l-29.45 0l0 29.45q0 2.852-1.984 4.836t-4.836 1.984l-13.578 0q-2.852 0-4.836-1.984t-1.984-4.836l0-29.45l-29.45 0q-2.852 0-4.836-1.984t-1.984-4.836l0-13.578q0-2.852 1.984-4.836t4.836-1.984l29.45 0l0-29.45q0-2.852 1.984-4.836t4.836-1.984l13.578 0q2.852 0 4.836 1.984t1.984 4.836l0 29.45l29.45 0q2.852 0 4.836 1.984t1.984 4.836z",width:100,height:100};const iconTablet={path:"M45.322 90.706q0-1.86-1.302-3.224-1.364-1.364-3.224-1.364t-3.224 1.364-1.302 3.224q0 1.86 1.364 3.224 1.302 1.364 3.162 1.302 1.86.062 3.224-1.302t1.302-3.224zm27.218-11.346l0-68.014q0-.93-.682-1.612t-1.55-.682l-58.962 0q-.93 0-1.612.682t-.682 1.612l0 68.014q0 .93.682 1.612t1.612.62l58.962 0q.992-.062 1.612-.682t.62-1.55zm9.114-68.014l0 77.066q0 4.65-3.348 7.998t-7.998 3.348l-58.962 0q-4.65 0-7.998-3.348t-3.348-7.998l0-77.066q0-4.65 3.348-7.998t7.998-3.348l58.962 0q4.65 0 7.998 3.348t3.348 7.998z",width:81.852,height:100};
|
|
1469
1469
|
|
|
@@ -1741,7 +1741,7 @@ const StartCoordsAbsoluteValue=props=>{const{startCoords,onChange,pointLabels,on
|
|
|
1741
1741
|
|
|
1742
1742
|
const{getClockwiseAngle}=angles;function getStartCoords(graph){if("startCoords"in graph){return graph.startCoords}return undefined}function getDefaultGraphStartCoords(graph,range,step){switch(graph.type){case "absolute-value":return getAbsoluteValueCoords({...graph,startCoords:undefined},range,step);case "linear":case "ray":return getLineCoords({...graph,startCoords:undefined},range,step);case "vector":return getVectorCoords({...graph,startCoords:undefined},range,step);case "segment":return getSegmentCoords({...graph,startCoords:undefined},range,step);case "linear-system":return getLinearSystemCoords({...graph,startCoords:undefined},range,step);case "circle":const startCoords=getCircleCoords({...graph,startCoords:undefined});const radius=vector.length(vector.subtract(startCoords.radiusPoint,startCoords.center));return {center:startCoords.center,radius};case "sinusoid":return getSinusoidCoords({...graph,startCoords:undefined},range,step);case "exponential":{const{coords,asymptote}=getExponentialCoords({...graph,startCoords:undefined},range,step);return {coords,asymptote}}case "tangent":return getTangentCoords({...graph,startCoords:undefined},range,step);case "quadratic":return getQuadraticCoords({...graph,startCoords:undefined},range,step);case "point":return getPointCoords({...graph,startCoords:undefined},range,step);case "polygon":return getPolygonCoords({...graph,startCoords:undefined},range,step);case "angle":return getAngleCoords({graph:{...graph,startCoords:undefined},range,step});case "logarithm":{const{coords,asymptote}=getLogarithmCoords({...graph,startCoords:undefined},range,step);return {coords,asymptote}}default:return undefined}}const getSinusoidEquation=startCoords=>{const p1=startCoords[0];const p2=startCoords[1];const amplitude=p2[1]-p1[1];const angularFrequency=Math.PI/(2*(p2[0]-p1[0]));const phase=p1[0]*angularFrequency;const verticalOffset=p1[1];return "y = "+amplitude.toFixed(3)+"sin("+angularFrequency.toFixed(3)+"x - "+phase.toFixed(3)+") + "+verticalOffset.toFixed(3)};const getTangentEquation=startCoords=>{const p1=startCoords[0];const p2=startCoords[1];const amplitude=p2[1]-p1[1];const angularFrequency=Math.PI/(4*(p2[0]-p1[0]));const phase=p1[0]*angularFrequency;const verticalOffset=p1[1];return "y = "+amplitude.toFixed(3)+"tan("+angularFrequency.toFixed(3)+"x - "+phase.toFixed(3)+") + "+verticalOffset.toFixed(3)};const getQuadraticEquation=startCoords=>{const p1=startCoords[0];const p2=startCoords[1];const p3=startCoords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return "Division by zero error"}const a=(p3[0]*(p2[1]-p1[1])+p2[0]*(p1[1]-p3[1])+p1[0]*(p3[1]-p2[1]))/denom;const b=(p3[0]*p3[0]*(p1[1]-p2[1])+p2[0]*p2[0]*(p3[1]-p1[1])+p1[0]*p1[0]*(p2[1]-p3[1]))/denom;const c=(p2[0]*p3[0]*(p2[0]-p3[0])*p1[1]+p3[0]*p1[0]*(p3[0]-p1[0])*p2[1]+p1[0]*p2[0]*(p1[0]-p2[0])*p3[1])/denom;return "y = "+a.toFixed(3)+"x^2 + "+b.toFixed(3)+"x + "+c.toFixed(3)};const getLogarithmEquation=(coords,asymptote)=>{const p1=coords[0];const p2=coords[1];if(p1[1]===p2[1]){return "undefined (points share the same y)"}if(p1[0]===asymptote||p2[0]===asymptote){return "undefined (point on asymptote)"}const ratio=(p1[0]-asymptote)/(p2[0]-asymptote);if(ratio<=0){return "undefined (points on opposite sides of asymptote)"}const bExp=Math.log(ratio)/(p1[1]-p2[1]);const aExp=(p1[0]-asymptote)/Math.exp(bExp*p1[1]);if(!isFinite(bExp)||!isFinite(aExp)||aExp===0||bExp===0){return "undefined (invalid coefficients)"}const a=1/bExp;const b=1/aExp;const c=-asymptote/aExp;return "y = "+a.toFixed(3)+"ln("+b.toFixed(3)+"x + "+c.toFixed(3)+")"};const getAngleEquation=(startCoords,allowReflexAngles=false)=>{const vertex=startCoords[1];const roundedAngle=getClockwiseAngle(startCoords,allowReflexAngles).toFixed(0);return `${roundedAngle}\u00B0 angle at (${vertex[0]}, ${vertex[1]})`};const shouldShowStartCoordsUI=(graph,isStatic)=>{if(isStatic){return false}switch(graph.type){case "point":return graph.numPoints!=="unlimited";case "polygon":return graph.numSides!=="unlimited"&&graph.snapTo!=="angles"&&graph.snapTo!=="sides";case "none":return false;case "angle":case "circle":case "exponential":case "linear":case "linear-system":case "tangent":case "quadratic":case "ray":case "segment":case "sinusoid":case "absolute-value":case "logarithm":case "vector":return true;default:throw new UnreachableCaseError(graph)}};
|
|
1743
1743
|
|
|
1744
|
-
const StartCoordsAngle=props=>{const{startCoords,allowReflexAngles,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??"",index===2?newLabel:pointLabels[2]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$c.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$c.equationBody,children:getAngleEquation(startCoords,allowReflexAngles)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1],startCoords[2]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Vertex",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value,startCoords[2]]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[2],onChange:value=>onChange([startCoords[0],startCoords[1],value]),pointLabel:pointLabels[2],onPointLabelChange:newLabel=>updatePointLabel(2,newLabel)})]})};const styles$c=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.
|
|
1744
|
+
const StartCoordsAngle=props=>{const{startCoords,allowReflexAngles,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??"",index===2?newLabel:pointLabels[2]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$c.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$c.equationBody,children:getAngleEquation(startCoords,allowReflexAngles)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1],startCoords[2]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Vertex",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value,startCoords[2]]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[2],onChange:value=>onChange([startCoords[0],startCoords[1],value]),pointLabel:pointLabels[2],onPointLabelChange:newLabel=>updatePointLabel(2,newLabel)})]})};const styles$c=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.body.size.xsmall}});
|
|
1745
1745
|
|
|
1746
1746
|
const StartCoordsCircle=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const[radiusState,setRadiusState]=React.useState(startCoords.radius.toString());React.useEffect(()=>{setRadiusState(startCoords.radius.toString());},[startCoords.radius]);function handleRadiuschange(newValue){setRadiusState(newValue);if(isNaN(+newValue)||newValue===""||+newValue===0){return}onChange({center:startCoords.center,radius:parseFloat(newValue)});}return jsxRuntimeExports.jsxs(View,{style:styles$b.tile,children:[jsxRuntimeExports.jsxs(View,{style:styles$b.row,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Center:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords.center,labels:["x","y"],onChange:coord=>onChange({center:coord,radius:startCoords.radius})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(BodyText,{size:"medium",weight:"bold",tag:"label",style:styles$b.row,children:["Radius:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:radiusState,onChange:handleRadiuschange,style:styles$b.textField})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(BodyText,{size:"medium",weight:"bold",tag:"span",style:styles$b.row,children:["Radius point label:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$b.textField,children:jsxRuntimeExports.jsx(TextField,{"aria-label":"Radius point name",value:pointLabels[0]??"",placeholder:"Radius point",onChange:newLabel=>onChangePointLabels([newLabel])})})]})]})};const styles$b=StyleSheet.create({tile:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
|
|
1747
1747
|
|
|
@@ -1757,9 +1757,9 @@ const StartCoordsMultiline=props=>{const{startCoords,type,onChange,pointLabels,o
|
|
|
1757
1757
|
|
|
1758
1758
|
const StartCoordsPoint=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:startCoords.map((coord,index)=>jsxRuntimeExports.jsx(CoordInput,{label:`Point ${index+1}`,coord:coord,onChange:newCoord=>{const newStartCoords=[...startCoords];newStartCoords[index]=newCoord;onChange(newStartCoords);},pointLabel:pointLabels?.[index],onPointLabelChange:onChangePointLabels&&(newLabel=>{const next=Array.from({length:startCoords.length},(_,i)=>i===index?newLabel:pointLabels?.[i]??"");onChangePointLabels(next);})},index))})};
|
|
1759
1759
|
|
|
1760
|
-
const StartCoordsQuadratic=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??"",index===2?newLabel:pointLabels[2]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$a.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$a.equationBody,children:getQuadraticEquation(startCoords)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1],startCoords[2]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value,startCoords[2]]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 3",coord:startCoords[2],onChange:value=>onChange([startCoords[0],startCoords[1],value]),pointLabel:pointLabels[2],onPointLabelChange:newLabel=>updatePointLabel(2,newLabel)})]})};const styles$a=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.
|
|
1760
|
+
const StartCoordsQuadratic=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??"",index===2?newLabel:pointLabels[2]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$a.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$a.equationBody,children:getQuadraticEquation(startCoords)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1],startCoords[2]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value,startCoords[2]]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 3",coord:startCoords[2],onChange:value=>onChange([startCoords[0],startCoords[1],value]),pointLabel:pointLabels[2],onPointLabelChange:newLabel=>updatePointLabel(2,newLabel)})]})};const styles$a=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.body.size.xsmall}});
|
|
1761
1761
|
|
|
1762
|
-
const StartCoordsSinusoid=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$9.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$9.equationBody,children:getSinusoidEquation(startCoords)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)})]})};const styles$9=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.size.
|
|
1762
|
+
const StartCoordsSinusoid=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$9.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$9.equationBody,children:getSinusoidEquation(startCoords)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)})]})};const styles$9=StyleSheet.create({equationSection:{marginTop:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginTop:spacing.xSmall_8,paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8,fontSize:font.body.size.xsmall}});
|
|
1763
1763
|
|
|
1764
1764
|
const StartCoordsTangent=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$d.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{className:styles$d.equationBody,children:getTangentEquation(startCoords)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)})]})};
|
|
1765
1765
|
|
|
@@ -1769,7 +1769,7 @@ const StartCoordsSettingsInner=props=>{const{type,range,step,allowReflexAngles,o
|
|
|
1769
1769
|
|
|
1770
1770
|
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}}
|
|
1771
1771
|
|
|
1772
|
-
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:this.props.graph&&getStartCoords(this.props.graph),...this.props.graph&&"pointLabels"in this.props.graph&&this.props.graph.pointLabels?{pointLabels:this.props.graph.pointLabels}:{},...this.props.graph&&"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];}});}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",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:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(correct.type===newGraph.type){correct=mergeGraphs(correct,newGraph);}else {correct=newGraph;}this.props.onChange({correct:correct,graph:this.props.graph});}};graph=jsxRuntimeExports.jsx(InteractiveGraph,{...graphProps,containerSizeClass:sizeClass,apiOptions:{...this.props.apiOptions,isMobile:false}});equationString=InteractiveGraph.getEquationString(graphProps);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.valid});}return jsxRuntimeExports.jsx(Id,{children:graphId=>jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Answer type",labelSize:"medium",children:jsxRuntimeExports.jsx(GraphTypeSelector,{disabled:this.props.apiOptions?.editingDisabled??false,graphType:this.props.graph?.type??InteractiveGraph.defaultProps.userInput.type,onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",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}),isFeatureOn({apiOptions:this.props.apiOptions},"perseus-enable-point-label-field")&&!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)}}
|
|
1772
|
+
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:this.props.graph&&getStartCoords(this.props.graph),...this.props.graph&&"pointLabels"in this.props.graph&&this.props.graph.pointLabels?{pointLabels:this.props.graph.pointLabels}:{},...this.props.graph&&"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",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:correct,handleUserInput:newGraph=>{let correct=this.props.correct;invariant(newGraph!=null);if(correct.type===newGraph.type){correct=mergeGraphs(correct,newGraph);}else {correct=newGraph;}this.props.onChange({correct:correct,graph:this.props.graph});}};graph=jsxRuntimeExports.jsx(InteractiveGraph,{...graphProps,containerSizeClass:sizeClass,apiOptions:{...this.props.apiOptions,isMobile:false}});equationString=InteractiveGraph.getEquationString(graphProps);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.valid});}return jsxRuntimeExports.jsx(Id,{children:graphId=>jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Answer type",labelSize:"medium",children:jsxRuntimeExports.jsx(GraphTypeSelector,{disabled:this.props.apiOptions?.editingDisabled??false,graphType:this.props.graph?.type??InteractiveGraph.defaultProps.userInput.type,onChange:type=>{this.props.onChange({graph:{type},correct:{type}});}})}),jsxRuntimeExports.jsx(InteractiveGraphDescription,{ariaLabelValue:this.props.fullGraphAriaLabel??"",ariaDescriptionValue:this.props.fullGraphAriaDescription??"",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}),isFeatureOn({apiOptions:this.props.apiOptions},"perseus-enable-point-label-field")&&!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)}}
|
|
1773
1773
|
|
|
1774
1774
|
const gray98="#FAFAFA";const gray95="#F0F1F2";const gray85="#D6D8DA";const gray76="#BABEC2";const gray68="#888D93";const gray41="#626569";const gray17="#21242C";
|
|
1775
1775
|
|