@khanacademy/perseus 65.4.0 → 65.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +24 -22
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +23 -21
- package/dist/index.js.map +1 -1
- package/dist/widgets/interactive-graphs/backgrounds/axis-labels.d.ts +0 -10
- package/dist/widgets/interactive-graphs/backgrounds/axis-ticks.d.ts +0 -5
- package/dist/widgets/interactive-graphs/backgrounds/utils.d.ts +20 -0
- package/dist/widgets/interactive-graphs/graphs/components/arrowhead.d.ts +1 -0
- package/dist/widgets/interactive-graphs/graphs/components/vector.d.ts +1 -0
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +4 -0
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +0 -5
- package/dist/widgets/interactive-graphs/utils.d.ts +4 -0
- package/dist/widgets/radio/radio-component.d.ts +5 -2
- package/dist/widgets/radio/radio.class.new.d.ts +4 -1
- package/dist/widgets/radio/radio.d.ts +5 -2
- package/dist/widgets/radio/radio.ff.d.ts +92 -2
- package/dist/widgets/radio/util.d.ts +3 -0
- package/package.json +45 -45
package/dist/es/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import React__default, { useContext, forwardRef, useId, useImperativeHandle, useRef, useState, useEffect, createElement, createContext, useLayoutEffect } from 'react';
|
|
3
3
|
import * as KAS from '@khanacademy/kas';
|
|
4
4
|
import { MathInputI18nContext, DesktopKeypad, getCursorContext, CursorContext, getKeyTranslator, createMathField, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, keypadElementPropType } from '@khanacademy/math-input';
|
|
5
|
-
import { expressionLogic, getDecimalSeparator, PerseusError, Errors, isLabeledSVG, getDataUrl, getSvgUrl, getBaseUrl, getRealImageUrl, getImageSizeModern, approximateDeepEqual, pluck, Registry, CoreWidgetRegistry, getWidgetIdsFromContentByType, applyDefaultsToWidgets, mapObject, getDefaultAnswerArea, splitPerseusItem, passageRefLogic, usesNumCorrect, radioLogic, shuffle, random, GrapherUtil as GrapherUtil$1,
|
|
5
|
+
import { expressionLogic, getDecimalSeparator, PerseusError, Errors, isLabeledSVG, getDataUrl, getSvgUrl, getBaseUrl, getRealImageUrl, getImageSizeModern, approximateDeepEqual, pluck, Registry, CoreWidgetRegistry, getWidgetIdsFromContentByType, applyDefaultsToWidgets, mapObject, getDefaultAnswerArea, splitPerseusItem, passageRefLogic, usesNumCorrect, deepClone, radioLogic, shuffle, random, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, getMatrixSize, measurerLogic, shuffleSorter, traverse, applyDefaultsToWidget } from '@khanacademy/perseus-core';
|
|
6
6
|
export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
|
|
7
7
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
8
8
|
import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
|
|
@@ -1424,7 +1424,7 @@ const ApiOptions={propTypes:PropTypes.shape({isArticle:PropTypes.bool.isRequired
|
|
|
1424
1424
|
|
|
1425
1425
|
const getPromptJSON$t=(renderProps,userInput)=>{return {type:"expression",label:renderProps.visibleLabel,userInput:{value:userInput}}};
|
|
1426
1426
|
|
|
1427
|
-
const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};class Expression extends React.Component{getUserInput(){return normalizeTex(this.props.userInput)}getPromptJSON(){return getPromptJSON$t(this.props,this.getUserInput())}focusInputPath(inputPath){this.refs.input.focus();}blurInputPath(inputPath){if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}}insert(keyPressed){this.refs.input.insert(keyPressed);}setInputValue(path,newValue,cb){this.props.handleUserInput(newValue,cb);}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,value:this.props.userInput}}render(){if(this.props.apiOptions.customKeypad){return jsxRuntimeExports.jsxs(View,{className:css(styles$I.mobileLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsx(KeypadInput,{ref:"input",ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,value:this.props.userInput,keypadElement:this.props.keypadElement,onChange:this.changeAndTrack,onFocus:()=>{this.props.keypadElement?.configure(this.props.keypadConfiguration,()=>{if(this._isMounted){this._handleFocus();}});},onBlur:this._handleBlur})]})}const className=classNames$1({"perseus-widget-expression":true,"show-error-tooltip":this.state.showErrorTooltip});const{ERROR_MESSAGE,ERROR_TITLE}=this.context.strings;return jsxRuntimeExports.jsxs(View,{className:css(styles$I.desktopLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsxs("div",{className:className,onBlur:()=>this.state.invalid&&this.setState({showErrorTooltip:true,showErrorStyle:true}),onFocus:()=>this.setState({showErrorTooltip:false}),children:[jsxRuntimeExports.jsx(View,{style:a11y.srOnly,role:"alert",children:this.state.showErrorTooltip&&ERROR_TITLE+" "+ERROR_MESSAGE}),jsxRuntimeExports.jsx(Tooltip,{forceAnchorFocusivity:false,opened:this.state.showErrorTooltip,title:ERROR_TITLE,content:ERROR_MESSAGE,children:jsxRuntimeExports.jsx(MathInput,{ref:"input",value:this.props.userInput,onChange:this.changeAndTrack,convertDotToTimes:this.props.times,buttonSets:this.props.buttonSets,onFocus:this._handleFocus,onBlur:this._handleBlur,hasError:this.state.showErrorStyle,ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,extraKeys:this.props.keypadConfiguration?.extraKeys,onAnalyticsEvent:this.props.analytics?.onAnalyticsEvent??(async()=>{})})})]})]})}constructor(...args){super(...args),this._textareaId=`expression_textarea_${Date.now()}`,this._isMounted=false,this.displayName="Expression",this.state={invalid:false,showErrorTooltip:false,showErrorStyle:false},this.componentDidMount=()=>{document.addEventListener("mousedown",this._handleMouseDown);this._isMounted=true;if(this.refs.input){const isMobile=this.props.apiOptions.customKeypad;const container=ReactDOM__default.findDOMNode(this.refs.input);const selector=isMobile?".mq-textarea > span":"textarea";const inputElement=container.querySelector(selector);inputElement?.setAttribute("id",this._textareaId);}},this.componentDidUpdate=prevProps=>{if(!_.isEqual(this.props.userInput,prevProps.userInput)||!_.isEqual(this.props.functions,prevProps.functions)){this.setState({invalid:false,showErrorTooltip:false,showErrorStyle:false});if(!this.parse(this.props.userInput,this.props).parsed){this.setState({invalid:true});}}},this.componentWillUnmount=()=>{this._isMounted=false;},this._handleMouseDown=()=>{if(this._isMounted&&this.state.showErrorTooltip){this.setState({showErrorTooltip:false});}},this.parse=(value,props)=>{const options=_.pick(props||this.props,"functions");_.extend(options,{decimal_separator:getDecimalSeparator(this.context.locale)});return KAS.parse(normalizeTex(value),options)},this.changeAndTrack=(userInput,cb)=>{this.props.handleUserInput(normalizeTex(userInput),cb);this.props.trackInteraction();},this._handleFocus=()=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:expression-focused",payload:null});this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{if(this.props.apiOptions.customKeypad){this.refs.input.focus();}return true},this.getInputPaths=()=>{return [[]]};}}Expression.contextType=PerseusI18nContext;Expression.defaultProps={times:false,functions:[],buttonSets:["basic","trig","prealgebra","logarithms"],onFocus:()=>{},onBlur:()=>{},apiOptions:ApiOptions.defaults,linterContext:linterContextDefault,userInput:""};const styles$I=StyleSheet.create({mobileLabelInputWrapper:{padding:"15px 4px 0"},desktopLabelInputWrapper:{margin:"5px 5px 0"}});const ExpressionWithDependencies=React.forwardRef((props,ref)=>{const deps=useDependencies();return jsxRuntimeExports.jsx(Expression,{ref:ref,analytics:deps.analytics,...props})});function getUserInputFromSerializedState$
|
|
1427
|
+
const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};class Expression extends React.Component{getUserInput(){return normalizeTex(this.props.userInput)}getPromptJSON(){return getPromptJSON$t(this.props,this.getUserInput())}focusInputPath(inputPath){this.refs.input.focus();}blurInputPath(inputPath){if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}}insert(keyPressed){this.refs.input.insert(keyPressed);}setInputValue(path,newValue,cb){this.props.handleUserInput(newValue,cb);}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,value:this.props.userInput}}render(){if(this.props.apiOptions.customKeypad){return jsxRuntimeExports.jsxs(View,{className:css(styles$I.mobileLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsx(KeypadInput,{ref:"input",ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,value:this.props.userInput,keypadElement:this.props.keypadElement,onChange:this.changeAndTrack,onFocus:()=>{this.props.keypadElement?.configure(this.props.keypadConfiguration,()=>{if(this._isMounted){this._handleFocus();}});},onBlur:this._handleBlur})]})}const className=classNames$1({"perseus-widget-expression":true,"show-error-tooltip":this.state.showErrorTooltip});const{ERROR_MESSAGE,ERROR_TITLE}=this.context.strings;return jsxRuntimeExports.jsxs(View,{className:css(styles$I.desktopLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsxs("div",{className:className,onBlur:()=>this.state.invalid&&this.setState({showErrorTooltip:true,showErrorStyle:true}),onFocus:()=>this.setState({showErrorTooltip:false}),children:[jsxRuntimeExports.jsx(View,{style:a11y.srOnly,role:"alert",children:this.state.showErrorTooltip&&ERROR_TITLE+" "+ERROR_MESSAGE}),jsxRuntimeExports.jsx(Tooltip,{forceAnchorFocusivity:false,opened:this.state.showErrorTooltip,title:ERROR_TITLE,content:ERROR_MESSAGE,children:jsxRuntimeExports.jsx(MathInput,{ref:"input",value:this.props.userInput,onChange:this.changeAndTrack,convertDotToTimes:this.props.times,buttonSets:this.props.buttonSets,onFocus:this._handleFocus,onBlur:this._handleBlur,hasError:this.state.showErrorStyle,ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,extraKeys:this.props.keypadConfiguration?.extraKeys,onAnalyticsEvent:this.props.analytics?.onAnalyticsEvent??(async()=>{})})})]})]})}constructor(...args){super(...args),this._textareaId=`expression_textarea_${Date.now()}`,this._isMounted=false,this.displayName="Expression",this.state={invalid:false,showErrorTooltip:false,showErrorStyle:false},this.componentDidMount=()=>{document.addEventListener("mousedown",this._handleMouseDown);this._isMounted=true;if(this.refs.input){const isMobile=this.props.apiOptions.customKeypad;const container=ReactDOM__default.findDOMNode(this.refs.input);const selector=isMobile?".mq-textarea > span":"textarea";const inputElement=container.querySelector(selector);inputElement?.setAttribute("id",this._textareaId);}},this.componentDidUpdate=prevProps=>{if(!_.isEqual(this.props.userInput,prevProps.userInput)||!_.isEqual(this.props.functions,prevProps.functions)){this.setState({invalid:false,showErrorTooltip:false,showErrorStyle:false});if(!this.parse(this.props.userInput,this.props).parsed){this.setState({invalid:true});}}},this.componentWillUnmount=()=>{this._isMounted=false;},this._handleMouseDown=()=>{if(this._isMounted&&this.state.showErrorTooltip){this.setState({showErrorTooltip:false});}},this.parse=(value,props)=>{const options=_.pick(props||this.props,"functions");_.extend(options,{decimal_separator:getDecimalSeparator(this.context.locale)});return KAS.parse(normalizeTex(value),options)},this.changeAndTrack=(userInput,cb)=>{this.props.handleUserInput(normalizeTex(userInput),cb);this.props.trackInteraction();},this._handleFocus=()=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:expression-focused",payload:null});this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{if(this.props.apiOptions.customKeypad){this.refs.input.focus();}return true},this.getInputPaths=()=>{return [[]]};}}Expression.contextType=PerseusI18nContext;Expression.defaultProps={times:false,functions:[],buttonSets:["basic","trig","prealgebra","logarithms"],onFocus:()=>{},onBlur:()=>{},apiOptions:ApiOptions.defaults,linterContext:linterContextDefault,userInput:""};const styles$I=StyleSheet.create({mobileLabelInputWrapper:{padding:"15px 4px 0"},desktopLabelInputWrapper:{margin:"5px 5px 0"}});const ExpressionWithDependencies=React.forwardRef((props,ref)=>{const deps=useDependencies();return jsxRuntimeExports.jsx(Expression,{ref:ref,analytics:deps.analytics,...props})});function getUserInputFromSerializedState$h(serializedState){return normalizeTex(serializedState.value)}var Expression$1 = {name:"expression",displayName:"Expression / Equation",widget:ExpressionWithDependencies,transform:widgetOptions=>{const{times,functions,buttonSets,buttonsVisible,visibleLabel,ariaLabel,extraKeys}=widgetOptions;return {keypadConfiguration:{keypadType:"EXPRESSION",extraKeys,times},times,functions,buttonSets,buttonsVisible,visibleLabel,ariaLabel}},version:expressionLogic.version,isLintable:true,getOneCorrectAnswerFromRubric(rubric){const correctAnswers=(rubric.answerForms||[]).filter(answerForm=>answerForm.considered==="correct");if(correctAnswers.length===0){return}return correctAnswers[0].value},getUserInputFromSerializedState: getUserInputFromSerializedState$h};
|
|
1428
1428
|
|
|
1429
1429
|
class SimpleKeypadInput extends React.Component{componentDidMount(){this._isMounted=true;}componentWillUnmount(){this._isMounted=false;}focus(){this.inputRef.current?.focus(this.context.setKeypadActive);}blur(){this.inputRef.current?.blur();}getValue(){return this.props.value}render(){const _this=this;const{keypadElement,onFocus,value,...rest}=_this.props;return jsxRuntimeExports.jsx(KeypadInput,{ref:this.inputRef,keypadElement:keypadElement,onFocus:()=>{if(keypadElement){keypadElement.configure({keypadType:"FRACTION"},()=>{if(_this._isMounted){onFocus?.();}});}else {onFocus?.();}},value:value==null?"":""+value,...rest})}constructor(...args){super(...args),this._isMounted=false,this.inputRef=React.createRef();}}SimpleKeypadInput.contextType=KeypadContext;SimpleKeypadInput.propTypes={keypadElement:keypadElementPropType,onFocus:PropTypes.func,value:PropTypes.oneOfType([PropTypes.string,PropTypes.number])};
|
|
1430
1430
|
|
|
@@ -1670,7 +1670,7 @@ const{captureScratchpadTouchStart: captureScratchpadTouchStart$3}=Util;const Inp
|
|
|
1670
1670
|
${props.examples.slice(1).join(", or\n")}`.replaceAll("*","").replaceAll("$","").replaceAll("\\ \\text{pi}"," pi").replaceAll("\\ "," and "):"";const inputProps={id:id,"aria-describedby":shouldShowExamples?ariaId:undefined,ref:inputRef,className:getInputClassName(),labelText:props.labelText,value:props.value,onFocus:handleFocus,onBlur:handleBlur,disabled:disabled,style:props.style,onChange:props.onChange,onTouchStart:captureScratchpadTouchStart$3,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",spellCheck:"false"};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(TextInput,{...inputProps}),jsxRuntimeExports.jsx("span",{id:ariaId,style:{display:"none"},children:examplesAria})]})};const renderTooltipContent=()=>{return jsxRuntimeExports.jsx(TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter.pushContextStack(linterContext,"input-with-examples"),strings:context.strings})})})};const examplesContent=props.examples.length<=2?props.examples.join(" "):props.examples.map((example,index)=>{return index===0&&example.startsWith("**")?`${example}
|
|
1671
1671
|
`:`- ${example}`}).join("\n");const showExamplesTooltip=shouldShowExamples&&inputFocused;return jsxRuntimeExports.jsx(Tooltip,{content:renderTooltipContent(),opened:showExamplesTooltip,placement:"bottom",children:renderInput()})});
|
|
1672
1672
|
|
|
1673
|
-
const formExamples={integer:function(_,strings){return strings.integerExample},proper:function(options,strings){if(options.simplify==="optional"){return strings.properExample}return strings.simplifiedProperExample},improper:function(options,strings){if(options.simplify==="optional"){return strings.improperExample}return strings.simplifiedImproperExample},mixed:function(_,strings){return strings.mixedExample},decimal:function(_,strings){return strings.decimalExample},percent:function(_,strings){return strings.percentExample},pi:function(_,strings){return strings.piExample}};class InputNumber extends React.Component{getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$s(this.props,this.getUserInput())}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,currentValue:userInput.currentValue}}render(){if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:"input",value:this.props.userInput.currentValue,keypadElement:this.props.keypadElement,onChange:this.handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur});if(this.props.rightAlign){return jsxRuntimeExports.jsx("div",{className:"perseus-input-right-align",children:input})}return input}const inputStyles=[styles$F.default,this.props.size==="small"?styles$F.small:null,this.props.rightAlign?styles$F.rightAlign:styles$F.leftAlign];if(this.props.reviewMode&&!this.props.userInput.currentValue){inputStyles.push(styles$F.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:"input",value:this.props.userInput.currentValue,onChange:this.handleChange,style:inputStyles,examples:this.examples(),shouldShowExamples:this.shouldShowExamples(),onFocus:this._handleFocus,onBlur:this._handleBlur,id:this.props.widgetId,disabled:this.props.apiOptions.readOnly,linterContext:this.props.linterContext})}constructor(...args){super(...args),this.shouldShowExamples=()=>{return this.props.answerType!=="number"},this.handleChange=(newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);},this._handleFocus=()=>{this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{this.refs.input.focus();return true},this.focusInputPath=inputPath=>{this.refs.input.focus();},this.blurInputPath=inputPath=>{if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}},this.getInputPaths=()=>{return [[]]},this.setInputValue=(path,newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:linterContextDefault,userInput:{currentValue:""}};const styles$F=StyleSheet.create({default:{width:80,height:"auto"},small:{width:40},leftAlign:{paddingLeft:spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function transform$6(widgetOptions){const{simplify,size,answerType,rightAlign}=widgetOptions;return {simplify,size,answerType,rightAlign}}function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}function getUserInputFromSerializedState$
|
|
1673
|
+
const formExamples={integer:function(_,strings){return strings.integerExample},proper:function(options,strings){if(options.simplify==="optional"){return strings.properExample}return strings.simplifiedProperExample},improper:function(options,strings){if(options.simplify==="optional"){return strings.improperExample}return strings.simplifiedImproperExample},mixed:function(_,strings){return strings.mixedExample},decimal:function(_,strings){return strings.decimalExample},percent:function(_,strings){return strings.percentExample},pi:function(_,strings){return strings.piExample}};class InputNumber extends React.Component{getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$s(this.props,this.getUserInput())}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,currentValue:userInput.currentValue}}render(){if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:"input",value:this.props.userInput.currentValue,keypadElement:this.props.keypadElement,onChange:this.handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur});if(this.props.rightAlign){return jsxRuntimeExports.jsx("div",{className:"perseus-input-right-align",children:input})}return input}const inputStyles=[styles$F.default,this.props.size==="small"?styles$F.small:null,this.props.rightAlign?styles$F.rightAlign:styles$F.leftAlign];if(this.props.reviewMode&&!this.props.userInput.currentValue){inputStyles.push(styles$F.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:"input",value:this.props.userInput.currentValue,onChange:this.handleChange,style:inputStyles,examples:this.examples(),shouldShowExamples:this.shouldShowExamples(),onFocus:this._handleFocus,onBlur:this._handleBlur,id:this.props.widgetId,disabled:this.props.apiOptions.readOnly,linterContext:this.props.linterContext})}constructor(...args){super(...args),this.shouldShowExamples=()=>{return this.props.answerType!=="number"},this.handleChange=(newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);},this._handleFocus=()=>{this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{this.refs.input.focus();return true},this.focusInputPath=inputPath=>{this.refs.input.focus();},this.blurInputPath=inputPath=>{if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}},this.getInputPaths=()=>{return [[]]},this.setInputValue=(path,newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:linterContextDefault,userInput:{currentValue:""}};const styles$F=StyleSheet.create({default:{width:80,height:"auto"},small:{width:40},leftAlign:{paddingLeft:spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function transform$6(widgetOptions){const{simplify,size,answerType,rightAlign}=widgetOptions;return {simplify,size,answerType,rightAlign}}function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}function getUserInputFromSerializedState$g(serializedState){return {currentValue:serializedState.currentValue}}var InputNumber$1 = {name:"input-number",displayName:"Input number (deprecated - use numeric input instead)",hidden:true,widget:InputNumber,isLintable:true,transform: transform$6,getOneCorrectAnswerFromRubric,getUserInputFromSerializedState: getUserInputFromSerializedState$g};
|
|
1674
1674
|
|
|
1675
1675
|
const getPromptJSON$r=(renderProps,userInput)=>{return {type:"numeric-input",label:renderProps.labelText,userInput:{value:userInput.currentValue}}};
|
|
1676
1676
|
|
|
@@ -1678,7 +1678,7 @@ const NumericExampleStrings={integer:(form,strings)=>strings.integerExample,prop
|
|
|
1678
1678
|
|
|
1679
1679
|
const NumericInputComponent=forwardRef((props,ref)=>{const context=useContext(PerseusI18nContext);const inputRef=useRef(null);const[isFocused,setIsFocused]=useState(false);useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current?.focus();setIsFocused(true);}},blur:()=>{if(inputRef.current){inputRef.current?.blur();setIsFocused(false);}}}));const handleChange=newValue=>{props.handleUserInput({currentValue:newValue});props.trackInteraction();};const handleFocus=()=>{props.onFocus([]);setIsFocused(true);};const handleBlur=()=>{props.onBlur([]);setIsFocused(false);};const styles=StyleSheet.create({inputWithExamples:{borderRadius:"3px",borderWidth:isFocused?"2px":"1px",display:"inline-block",fontFamily:`Symbola, "Times New Roman", serif`,fontSize:"18px",height:"32px",lineHeight:"18px",padding:isFocused?"4px":"4px 5px",textAlign:props.rightAlign?"right":"left",width:props.size==="small"?40:80}});if(props.apiOptions.customKeypad){const alignmentClass=props.rightAlign?"perseus-input-right-align":undefined;return jsxRuntimeExports.jsx("div",{className:alignmentClass,children:jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:inputRef,value:props.userInput.currentValue,keypadElement:props.keypadElement,onChange:handleChange,onFocus:handleFocus,onBlur:handleBlur})})}return jsxRuntimeExports.jsx(InputWithExamples,{ref:inputRef,value:props.userInput.currentValue,onChange:handleChange,labelText:props.labelText,examples:generateExamples(props.answerForms,context.strings),shouldShowExamples:shouldShowExamples(props.answerForms),onFocus:handleFocus,onBlur:handleBlur,id:props.widgetId,disabled:props.apiOptions.readOnly,style:styles.inputWithExamples})});
|
|
1680
1680
|
|
|
1681
|
-
class NumericInput extends React.Component{getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$r(this.props,this.getUserInput())}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,currentValue:userInput.currentValue}}render(){return jsxRuntimeExports.jsx(NumericInputComponent,{...this.props,ref:this.inputRef})}constructor(...args){super(...args),this.inputRef=React.createRef(),this.focus=()=>{this.inputRef.current?.focus();return true},this.focusInputPath=()=>{this.inputRef.current?.focus();},this.blurInputPath=()=>{this.inputRef.current?.blur();},this.getInputPaths=()=>{return [[]]},this.setInputValue=(path,newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);};}}NumericInput.defaultProps={size:"normal",rightAlign:false,apiOptions:ApiOptions.defaults,coefficient:false,answerForms:[],labelText:"",linterContext:linterContextDefault,userInput:{currentValue:""}};const propsTransform=function(widgetOptions){const{answers:_,...rendererProps}={...widgetOptions,answerForms:unionAnswerForms(widgetOptions.answers.filter(answer=>answer.status==="correct").map(answer=>{return (answer.answerForms||[]).map(form=>{return {simplify:answer.simplify,name:form}})}))};return rendererProps};function getUserInputFromSerializedState$
|
|
1681
|
+
class NumericInput extends React.Component{getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$r(this.props,this.getUserInput())}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,currentValue:userInput.currentValue}}render(){return jsxRuntimeExports.jsx(NumericInputComponent,{...this.props,ref:this.inputRef})}constructor(...args){super(...args),this.inputRef=React.createRef(),this.focus=()=>{this.inputRef.current?.focus();return true},this.focusInputPath=()=>{this.inputRef.current?.focus();},this.blurInputPath=()=>{this.inputRef.current?.blur();},this.getInputPaths=()=>{return [[]]},this.setInputValue=(path,newValue,cb)=>{this.props.handleUserInput({currentValue:newValue},cb);};}}NumericInput.defaultProps={size:"normal",rightAlign:false,apiOptions:ApiOptions.defaults,coefficient:false,answerForms:[],labelText:"",linterContext:linterContextDefault,userInput:{currentValue:""}};const propsTransform=function(widgetOptions){const{answers:_,...rendererProps}={...widgetOptions,answerForms:unionAnswerForms(widgetOptions.answers.filter(answer=>answer.status==="correct").map(answer=>{return (answer.answerForms||[]).map(form=>{return {simplify:answer.simplify,name:form}})}))};return rendererProps};function getUserInputFromSerializedState$f(serializedState){return {currentValue:serializedState.currentValue}}var NumericInput$1 = {name:"numeric-input",displayName:"Numeric input",widget:NumericInput,transform:propsTransform,isLintable:true,getOneCorrectAnswerFromRubric(rubric){const correctAnswers=rubric.answers.filter(answer=>answer.status==="correct");const answerStrings=correctAnswers.map(answer=>{const format=answer.answerForms&&answer.answerForms[0]?answer.answerForms[0]:"decimal";let answerString=KhanMath.toNumericString(answer.value,format);if(answer.maxError){answerString+=" ± "+KhanMath.toNumericString(answer.maxError,format);}return answerString});if(answerStrings.length===0){return}return answerStrings[0]},getUserInputFromSerializedState: getUserInputFromSerializedState$f};
|
|
1682
1682
|
|
|
1683
1683
|
const getPromptJSON$q=(renderProps,userInput)=>{const choices=renderProps.choices||[];const options=choices.map(choice=>{const option={value:choice.content};if(choice.rationale){option.rationale=choice.rationale;}return option});return {type:"radio",hasNoneOfTheAbove:!!renderProps.hasNoneOfTheAbove,options,userInput:{selectedOptions:userInput.choicesSelected.slice()}}};
|
|
1684
1684
|
|
|
@@ -1722,7 +1722,7 @@ function getA11yText$1(letter,checked,correct,showCorrectness,strings){if(showCo
|
|
|
1722
1722
|
|
|
1723
1723
|
const FocusRing=function({visible=true,color=kaGreen,multipleSelect=false,children}){const borderColor=visible?color:"transparent";const borderRadius=multipleSelect?5:"50%";const style={borderColor,borderRadius};return jsxRuntimeExports.jsx("span",{"data-testid":"focus-ring",className:css(styles$A.ring),style:style,children:children})};const styles$A=StyleSheet.create({ring:{margin:"auto",display:"inline-block",borderWidth:2,padding:2,borderStyle:"solid"}});
|
|
1724
1724
|
|
|
1725
|
-
function getChoiceLetter$1(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}
|
|
1725
|
+
function getChoiceLetter$1(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}function getUserInputFromSerializedState$e(props,unshuffle=true){if(props.choiceStates){const choiceStates=props.choiceStates;const choicesSelected=choiceStates.map(()=>false);for(let i=0;i<choicesSelected.length;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=choiceStates[i].selected;}return {choicesSelected}}const{values}=props;if(values){const choicesSelected=[...values];const valuesLength=values.length;for(let i=0;i<valuesLength;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=values[i];}return {choicesSelected}}return {choicesSelected:props.choices.map(()=>false)}}
|
|
1726
1726
|
|
|
1727
1727
|
const CHOICE_ICON_SIZE$1=24;const styles$z=StyleSheet.create({iconWrapper:{display:"inline-block",position:"relative"}});
|
|
1728
1728
|
|
|
@@ -1736,7 +1736,7 @@ const ChoiceNoneAbove$1=function({content,forwardedRef,showContent=true,...rest}
|
|
|
1736
1736
|
|
|
1737
1737
|
const{captureScratchpadTouchStart: captureScratchpadTouchStart$2}=Util;function getInstructionsText$1(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer}const BaseRadio$1=function({apiOptions,reviewModeRubric,reviewMode,choices,editMode=false,multipleSelect=false,labelWrap,countChoices,numCorrect,isLastUsedWidget,onChange,registerFocusFunction}){const{strings}=usePerseusI18n();const prevReviewModeRubric=useRef();const choiceRefs=useRef([]);useEffect(()=>{if(apiOptions.canScrollPage&&isLastUsedWidget&&reviewModeRubric&&!prevReviewModeRubric.current){const checkedIndex=choices.findIndex(c=>c.checked);if(checkedIndex>=0){const ref=choiceRefs.current[checkedIndex];const anyNode=ReactDOM__default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){scrollElementIntoView(buttonNode);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,choices,isLastUsedWidget,reviewModeRubric]);function updateChoice(choiceIndex,newValues){let newCheckedList;if(newValues.checked&&!multipleSelect){newCheckedList=choices.map(_=>false);}else {newCheckedList=choices.map(c=>c.checked);}newCheckedList[choiceIndex]=newValues.checked;onChange({checked:newCheckedList});}registerFocusFunction?.(choiceIndex=>{const ref=choiceRefs.current[choiceIndex||0];const anyNode=ReactDOM__default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){buttonNode.focus();}else {return false}return true});const isMobile=apiOptions.isMobile;const firstChoiceHighlighted=choices[0].highlighted;const lastChoiceHighlighted=choices[choices.length-1].highlighted;const className=classNames$1("perseus-widget-radio",!editMode&&"perseus-rendered-radio",css(styles$v.radio,styles$v.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$v.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$v.radioContainerLastHighlighted));const instructionsClassName=classNames$1("instructions",css(styles$v.instructions,isMobile&&styles$v.instructionsMobile));const instructions=getInstructionsText$1(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=css(styles$v.responsiveFieldset);const fieldset=jsxRuntimeExports.jsxs("fieldset",{className:`perseus-widget-radio-fieldset ${responsiveClassName}`,children:[jsxRuntimeExports.jsx("legend",{className:"perseus-sr-only",children:instructions}),jsxRuntimeExports.jsx("div",{className:instructionsClassName,"aria-hidden":"true",children:instructions}),jsxRuntimeExports.jsx("ul",{className:className,style:{listStyle:"none"},children:choices.map((choice,i)=>{let Element=Choice$2;const ref=React.createRef();choiceRefs.current[i]=ref;const elementProps={apiOptions:apiOptions,multipleSelect:multipleSelect,checked:choice.checked,previouslyAnswered:choice.previouslyAnswered,reviewMode,correct:choice.correct,rationale:choice.rationale,content:choice.content,disabled:apiOptions.readOnly||choice.disabled,showCorrectness:reviewMode||!!choice.showCorrectness,showRationale:choice.hasRationale&&(reviewMode||choice.showRationale),pos:i,onChange:newValues=>{if(editMode){return}updateChoice(i,newValues);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$2;_.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return css(styles$v.item,styles$v.responsiveItem,checked&&styles$v.selectedItem,checked&&choice.highlighted&&styles$v.aboveBackdrop,checked&&choice.highlighted&&apiOptions.isMobile&&styles$v.aboveBackdropMobile,nextChoiceHighlighted&&apiOptions.isMobile&&styles$v.nextHighlighted)};aphroditeClassName(true);let correctnessClass;if(reviewMode&&reviewModeRubric){correctnessClass=reviewModeRubric.choices[i].correct?ClassNames.CORRECT:ClassNames.INCORRECT;}const className=classNames$1(aphroditeClassName(choice.checked),ClassNames.RADIO.OPTION,choice.checked&&ClassNames.RADIO.SELECTED,correctnessClass);let listElem=null;let clickHandler;if(editMode){clickHandler=e=>{let elem=e.target;while(elem&&elem!==listElem){if(elem.getAttribute("data-is-radio-icon")){updateChoice(i,{checked:!choice.checked});return}elem=elem.parentNode;}};}return jsxRuntimeExports.jsx("li",{ref:e=>listElem=e,className:className,onClick:clickHandler,onTouchStart:labelWrap?undefined:captureScratchpadTouchStart$2,children:jsxRuntimeExports.jsx(Element,{...elementProps,ref:ref})},i)})})]});return jsxRuntimeExports.jsx("div",{className:css(styles$v.responsiveContainer),children:fieldset})};const styles$v=StyleSheet.create({instructions:{display:"block",color:gray17,fontSize:14,lineHeight:1.25,fontFamily:"inherit",fontStyle:"normal",fontWeight:"bold",marginBottom:16},instructionsMobile:{fontSize:18,[mediaQueries.smOrSmaller]:{fontSize:16},[mediaQueries.xl]:{fontSize:20}},radio:{padding:0},responsiveRadioContainer:{borderBottom:`1px solid ${radioBorderColor$1}`,borderTop:`1px solid ${radioBorderColor$1}`,width:"auto",[mediaQueries.smOrSmaller]:{marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin}},radioContainerFirstHighlighted:{borderTop:`1px solid rgba(0, 0, 0, 0)`},radioContainerLastHighlighted:{borderBottom:`1px solid rgba(0, 0, 0, 0)`},item:{marginLeft:20},responsiveItem:{marginLeft:0,padding:0,":not(:last-child)":{borderBottom:`1px solid ${radioBorderColor$1}`}},selectedItem:{background:"white"},aboveBackdrop:{position:"relative",zIndex:1062},aboveBackdropMobile:{boxShadow:"0 0 4px 0 rgba(0, 0, 0, 0.2),"+"0 0 2px 0 rgba(0, 0, 0, 0.1)",":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},nextHighlighted:{":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},responsiveContainer:{overflow:"auto",marginLeft:negativePhoneMargin,paddingLeft:phoneMargin},responsiveFieldset:{paddingRight:phoneMargin,minWidth:"auto"}});
|
|
1738
1738
|
|
|
1739
|
-
let Radio$3 = class Radio extends React.Component{
|
|
1739
|
+
let Radio$3 = class Radio extends React.Component{focus(choiceIndex){if(this.focusFunction){return this.focusFunction(choiceIndex)}return false}registerFocusFunction(fun){this.focusFunction=fun;}getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const{choices}=this.props;const{strings}=this.context;let choiceStates;if(this.props.static){choiceStates=choices.map(choice=>({selected:!!choice.correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.showSolutions==="all"){choiceStates=choices.map(({correct})=>({selected:!!correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.choiceStates){choiceStates=this.props.choiceStates;}else if(this.props.values){choiceStates=this.props.values.map(val=>({selected:val,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}else {choiceStates=choices.map(()=>({selected:false,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}const choicesProp=choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=this.props.reviewModeRubric?.choices[i];return {content:this._renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this._renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(this.props.questionCompleted&&selected),highlighted,previouslyAnswered:previouslyAnswered}});return jsxRuntimeExports.jsx(BaseRadio$1,{labelWrap:true,multipleSelect:this.props.multipleSelect,countChoices:this.props.countChoices,numCorrect:this.props.numCorrect,choices:choicesProp,onChange:this.updateChoices,reviewModeRubric:this.props.reviewModeRubric,reviewMode:this.props.reviewMode,deselectEnabled:this.props.deselectEnabled,apiOptions:this.props.apiOptions,isLastUsedWidget:this.props.isLastUsedWidget,registerFocusFunction:i=>this.registerFocusFunction(i)})}constructor(...args){super(...args),this._renderRenderer=(content="")=>{let nextPassageRefId=1;const widgets={};const modContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(match,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;widgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return jsxRuntimeExports.jsx(Renderer,{content:modContent,widgets:widgets,findExternalWidgets:this.props.findWidgets,alwaysUpdate:true,linterContext:{...this.props.linterContext,blockHighlight:true},strings:this.context.strings},"choiceContentRenderer")},this.updateChoices=newValueLists=>{const{choiceStates,choices}=this.props;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{choiceState.selected=newValueLists.checked[i];});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$3.contextType=PerseusI18nContext;Radio$3.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:linterContextDefault,showSolutions:"none"};
|
|
1740
1740
|
|
|
1741
1741
|
var styles$u = {"scrollButtonsContainer":"perseus_kjDHiWdD","scrollFade":"perseus_KB5rz4XY","scrollFadeLeft":"perseus_tP0ytdCp","scrollFadeRight":"perseus_t5yijnoR"};
|
|
1742
1742
|
|
|
@@ -1762,11 +1762,11 @@ const getChoiceStates=({choices,isStatic,showSolutions,choiceStates,values})=>{c
|
|
|
1762
1762
|
|
|
1763
1763
|
const defaultProps={multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:linterContextDefault,showSolutions:"none"};const RadioComponent=({choices,multipleSelect=defaultProps.multipleSelect,countChoices=defaultProps.countChoices,deselectEnabled=defaultProps.deselectEnabled,linterContext=defaultProps.linterContext,showSolutions=defaultProps.showSolutions,static:isStatic,reviewModeRubric,reviewMode,apiOptions,isLastUsedWidget,questionCompleted,findWidgets,onChange,trackInteraction,numCorrect,choiceStates,values})=>{const{strings}=useContext(PerseusI18nContext);useEffect(()=>{console.log("New Radio Component");},[]);const renderRenderer=(content="")=>{const{parsedContent,extractedWidgets}=parseNestedWidgets(content);return jsxRuntimeExports.jsx(Renderer,{content:parsedContent,widgets:extractedWidgets,findExternalWidgets:findWidgets,alwaysUpdate:true,linterContext:{...linterContext,blockHighlight:true},strings:strings},"choiceContentRenderer")};const updateChoices=newValueLists=>{const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{choiceState.selected=newValueLists.checked[i];});onChange({choiceStates:newChoiceStates});trackInteraction();};const buildChoiceProps=(choices,choiceStates)=>{return choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=reviewModeRubric?.choices[i];return {content:renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(questionCompleted&&selected),highlighted,previouslyAnswered}})};const updatedChoiceStates=getChoiceStates({choices,isStatic,showSolutions,choiceStates,values});const updatedChoicesProp=buildChoiceProps(choices,updatedChoiceStates);return jsxRuntimeExports.jsx(BaseRadio,{labelWrap:true,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:updatedChoicesProp,onChange:updateChoices,reviewModeRubric:reviewModeRubric,reviewMode:reviewMode,deselectEnabled:deselectEnabled,apiOptions:apiOptions,isLastUsedWidget:isLastUsedWidget})};
|
|
1764
1764
|
|
|
1765
|
-
let Radio$2 = class Radio extends React.Component{
|
|
1765
|
+
let Radio$2 = class Radio extends React.Component{getUserInput(){return this.props.userInput}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){return jsxRuntimeExports.jsx(RadioComponent,{...this.props})}};Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:linterContextDefault,showSolutions:"none"};
|
|
1766
1766
|
|
|
1767
|
-
let Radio$1 = class Radio extends Radio$3{focus(choiceIndex){if(this.radioRef.current?.focus){return this.radioRef.current.focus(choiceIndex)}return false}render(){return this.ffIsOn?jsxRuntimeExports.jsx(Radio$2,{...
|
|
1767
|
+
let Radio$1 = class Radio extends Radio$3{getSerializedState(){const{userInput:_,...rest}=this._mergePropsAndState();return {...rest}}_handleChange(arg){const newChoiceStates=arg.choiceStates;if(newChoiceStates){this.setState({choiceStates:newChoiceStates.map(choiceState=>{const{selected:_,...rest}=choiceState;return {...rest}})},()=>{const props=this._mergePropsAndState();const mergedProps={...props,choiceStates:deepClone(props.choiceStates||[]).map((choiceState,index)=>{return {...choiceState,selected:newChoiceStates[index].selected}})};const unshuffledUserInput=getUserInputFromSerializedState$e(mergedProps);this.props.handleUserInput(unshuffledUserInput);});}else {throw new Error("unhandled onChange call in Radio!")}}_mergePropsAndState(){return {...this.props,choiceStates:this.state.choiceStates?.map((choiceState,index)=>{const choice=this.props.choices[index];const selected=this.props.userInput.choicesSelected[choice.originalIndex];return {...choiceState,selected}}),onChange:arg=>this._handleChange(arg)}}focus(choiceIndex){if(this.radioRef.current?.focus){return this.radioRef.current.focus(choiceIndex)}return false}render(){const props=this._mergePropsAndState();return this.ffIsOn?jsxRuntimeExports.jsx(Radio$2,{...props}):jsxRuntimeExports.jsx(Radio$3,{ref:this.radioRef,...props})}constructor(props){super(props),this.ffIsOn=false,this.radioRef=React.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:props.choices.map(()=>({highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}))};}};
|
|
1768
1768
|
|
|
1769
|
-
const _choiceTransform=(widgetOptions,strings,problemNum)=>{const _maybeRandomize=function(array){const randomSeed=problemNum===undefined?random:problemNum;return widgetOptions.randomize?shuffle(array,randomSeed??0):array};const _addNoneOfAbove=function(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices};const enforceOrdering=choices=>{const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices};const choices=widgetOptions.choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return _addNoneOfAbove(enforceOrdering(_maybeRandomize(choices)))};const transform$5=(widgetOptions,strings,problemNum)=>{const choices=_choiceTransform(widgetOptions,strings,problemNum);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:_.pluck(choices,"correct")}};var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,transform: transform$5,staticTransform:transform$5,version:radioLogic.version,isLintable:true,getUserInputFromSerializedState:
|
|
1769
|
+
const _choiceTransform=(widgetOptions,strings,problemNum)=>{const _maybeRandomize=function(array){const randomSeed=problemNum===undefined?random:problemNum;return widgetOptions.randomize?shuffle(array,randomSeed??0):array};const _addNoneOfAbove=function(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices};const enforceOrdering=choices=>{const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices};const choices=widgetOptions.choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return _addNoneOfAbove(enforceOrdering(_maybeRandomize(choices)))};const transform$5=(widgetOptions,strings,problemNum)=>{const choices=_choiceTransform(widgetOptions,strings,problemNum);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:_.pluck(choices,"correct")}};function getStartUserInput$8(options){return {choicesSelected:options.choices.map(()=>false)}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,transform: transform$5,staticTransform:transform$5,getStartUserInput: getStartUserInput$8,version:radioLogic.version,isLintable:true,getUserInputFromSerializedState: getUserInputFromSerializedState$e};
|
|
1770
1770
|
|
|
1771
1771
|
var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
|
|
1772
1772
|
|
|
@@ -1866,15 +1866,17 @@ const defaultGraphConfig={range:[[0,1],[0,1]],tickStep:[1,1],gridStep:[1,1],snap
|
|
|
1866
1866
|
|
|
1867
1867
|
const matrixBuilder=vec.matrixBuilder;function vectorsToPixels(vectors,graphState,translation=[0,0]){const{range,width,height}=graphState;const[[xMin,xMax],[yMin,yMax]]=range;const transformToPx=matrixBuilder().translate(...translation).scale(width/(xMax-xMin),-height/(yMax-yMin)).get();return vectors.map(p=>vec.transform(p,transformToPx))}function dimensionsToPixels(dimens,graphState){const{range,width,height}=graphState;const[[xMin,xMax],[yMin,yMax]]=range;const transformToPx=matrixBuilder().scale(width/(xMax-xMin),height/(yMax-yMin)).get();return dimens.map(d=>vec.transform(d,transformToPx))}function pointToPixel(point,graphState){const[[xMin],[,yMax]]=graphState.range;const[a,b]=[-xMin,-yMax];return vectorsToPixels([point],graphState,[a,b])[0]}const useTransformVectorsToPixels=(...vectors)=>{const graphState=useGraphConfig();return vectorsToPixels(vectors,graphState)};const useTransformDimensionsToPixels=(...dimens)=>{const graphState=useGraphConfig();return dimensionsToPixels(dimens,graphState)};function pixelsToVectors(pixels,graphState){const[[xMin,xMax],[yMin,yMax]]=graphState.range;const{width,height}=graphState;const xSpan=xMax-xMin;const ySpan=yMax-yMin;return pixels.map(pixel=>{const x=pixel[X]/width*xSpan+xMin;const y=yMax-pixel[Y]/height*ySpan;return [x,y]})}
|
|
1868
1868
|
|
|
1869
|
-
const arrowPath=pathBuilder().move(-3,4).curve(-2.75,2.5,0,.25,.75,0).curve(0,-0.25,-2.75,-2.5,-3,-4).scale(1.4).build();function Arrowhead(props){const[point]=useTransformVectorsToPixels(props.tip);return jsxRuntimeExports.jsx("g",{"aria-hidden":true,className:"interactive-graph-arrowhead",transform:`translate(${point[X]} ${point[Y]}) rotate(${props.angle})`,children:jsxRuntimeExports.jsx("g",{transform:"translate(-1.5)",children:jsxRuntimeExports.jsx("path",{d:arrowPath,fill:"none",style:{stroke:props.color??"inherit"},strokeLinejoin:"round",strokeLinecap:"round",strokeWidth
|
|
1869
|
+
const arrowPath=pathBuilder().move(-3,4).curve(-2.75,2.5,0,.25,.75,0).curve(0,-0.25,-2.75,-2.5,-3,-4).scale(1.4).build();function Arrowhead(props){const[point]=useTransformVectorsToPixels(props.tip);return jsxRuntimeExports.jsx("g",{"aria-hidden":true,className:"interactive-graph-arrowhead",transform:`translate(${point[X]} ${point[Y]}) rotate(${props.angle})`,children:jsxRuntimeExports.jsx("g",{transform:"translate(-1.5)",children:jsxRuntimeExports.jsx("path",{d:arrowPath,fill:"none",style:{stroke:props.color??"inherit"},strokeLinejoin:"round",strokeLinecap:"round",strokeWidth:`${props.strokeWidth??2}px`})})})}
|
|
1870
1870
|
|
|
1871
1871
|
function AxisArrows(){const{range:[[xMin,xMax],[yMin,yMax]]}=useGraphConfig();const axisColor="var(--mafs-fg)";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[!(yMin>0||yMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMin,0],angle:180}),jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMax,0],angle:0})]}),!(xMin>0||xMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMin],angle:90}),jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMax],angle:270})]})]})}
|
|
1872
1872
|
|
|
1873
|
-
const TARGET_SIZE=44;const REMOVE_BUTTON_ID="perseus_mafs_remove_button";const normalizePoints=(range,step,coordsList,noSnap)=>coordsList.map(coords=>coords.map((coord,i)=>{const axisRange=range[i];if(noSnap){return axisRange[MIN]+size(axisRange)*coord}const axisStep=step[i];const nSteps=Math.floor(size(axisRange)/axisStep);const tick=Math.round(coord*nSteps);return axisRange[MIN]+axisStep*tick}));const normalizeCoords=(coordsList,ranges)=>coordsList.map(coords=>coords.map((coord,i)=>{return (coord+ranges[i][1])/size(ranges[i])}));function bound$1({snapStep,range,point}){const boundingBox=inset(snapStep,range);return clampToBox(boundingBox,point)}function isUnlimitedGraphState(state){return state.type==="point"&&state.numPoints==="unlimited"||state.type==="polygon"&&state.numSides==="unlimited"}const mathOnlyParser=SimpleMarkdown.parserFor({math:{...pureMarkdownRules.math,order:0},text:{order:1,match:SimpleMarkdown.anyScopeRegex(/^([^$\\{}]+)/),parse:capture=>({content:capture[0]})},specialCharacter:{order:2,match:SimpleMarkdown.anyScopeRegex(/^(\\[\S\s]|\$|\\$|{|})/),parse:capture=>({content:capture[0]})}},{inline:true});function replaceOutsideTeX(mathString){const parsed=mathOnlyParser(mathString);let result="";for(const piece of parsed){piece.type==="math"?result+="$"+piece.content+"$":piece.type==="specialCharacter"?result+=escapeIfUnescaped(piece.content):result+=piece.content;}return `\\text{${result}}`}function escapeIfUnescaped(character){if(character.length===1){return "\\"+character}else {return character}}
|
|
1873
|
+
const TARGET_SIZE=44;const REMOVE_BUTTON_ID="perseus_mafs_remove_button";const normalizePoints=(range,step,coordsList,noSnap)=>coordsList.map(coords=>coords.map((coord,i)=>{const axisRange=range[i];if(noSnap){return axisRange[MIN]+size(axisRange)*coord}const axisStep=step[i];const nSteps=Math.floor(size(axisRange)/axisStep);const tick=Math.round(coord*nSteps);return axisRange[MIN]+axisStep*tick}));const normalizeCoords=(coordsList,ranges)=>coordsList.map(coords=>coords.map((coord,i)=>{return (coord+ranges[i][1])/size(ranges[i])}));function bound$1({snapStep,range,point}){const boundingBox=inset(snapStep,range);return clampToBox(boundingBox,point)}function isUnlimitedGraphState(state){return state.type==="point"&&state.numPoints==="unlimited"||state.type==="polygon"&&state.numSides==="unlimited"}const mathOnlyParser=SimpleMarkdown.parserFor({math:{...pureMarkdownRules.math,order:0},text:{order:1,match:SimpleMarkdown.anyScopeRegex(/^([^$\\{}]+)/),parse:capture=>({content:capture[0]})},specialCharacter:{order:2,match:SimpleMarkdown.anyScopeRegex(/^(\\[\S\s]|\$|\\$|{|})/),parse:capture=>({content:capture[0]})}},{inline:true});function replaceOutsideTeX(mathString){const parsed=mathOnlyParser(mathString);let result="";for(const piece of parsed){piece.type==="math"?result+="$"+piece.content+"$":piece.type==="specialCharacter"?result+=escapeIfUnescaped(piece.content):result+=piece.content;}return `\\text{${result}}`}function escapeIfUnescaped(character){if(character.length===1){return "\\"+character}else {return character}}const getRangeDiff=range=>{const[min,max]=range;return Math.abs(max-min)};const calculateNestedSVGCoords=(range,width,height)=>{let viewboxX=0;const totalXRange=getRangeDiff(range[X]);const gridCellWidth=width/totalXRange;const minX=range[X][MIN];if(minX>0){viewboxX=gridCellWidth*Math.abs(minX);}if(minX<0){viewboxX=-gridCellWidth*Math.abs(minX);}let viewboxY=-height;const totalYRange=getRangeDiff(range[Y]);const gridCellHeight=height/totalYRange;const minY=range[Y][MIN];if(minY>0){viewboxY=-height-gridCellHeight*Math.abs(minY);}if(minY<0){viewboxY=gridCellHeight*Math.abs(minY)-height;}return {viewboxX,viewboxY}};
|
|
1874
1874
|
|
|
1875
|
-
const fontSize=14;
|
|
1875
|
+
const fontSize=14;const clampLabelPosition=(labelPosition,graphInfo)=>{const x=Math.max(Math.min(labelPosition[X],graphInfo.width+fontSize*1.25),-14*1.5);const y=Math.max(Math.min(labelPosition[Y],graphInfo.height+fontSize*1.25),-14*2);return [x,y]};const getLabelTransform=labelLocation=>{const isOnAxis=labelLocation===undefined||labelLocation==="onAxis";const xLabelTransform=isOnAxis?"translate(7px, -50%)":"translate(-50%, -50%)";const yLabelTransform=isOnAxis?"translate(-50%, 0px)":"translate(-50%, 0px) rotate(-90deg)";return {xLabelTransform,yLabelTransform}};const calculateMaxDigitsInRange=(range,tickStep)=>{const maxDigitsInRange=Math.max(String(Math.abs(Math.floor(range[MIN]))).length,String(Math.abs(Math.ceil(range[MAX]))).length);const tickStepSigFigs=countSignificantDecimals(tickStep)+2;return Math.max(maxDigitsInRange,tickStepSigFigs)};const getLabelPosition=(graphInfo,labelLocation,tickStep)=>{if(labelLocation==="alongEdge"){const xAxisLabelOffset=graphInfo.range[Y][MIN]>=0?[0,fontSize*3]:[0,fontSize*1.5];const isRelativelyCloseToZero=graphInfo.range[X][MIN]<0&&Math.abs(graphInfo.range[X][MIN])<(graphInfo.range[X][MAX]-graphInfo.range[X][MIN])*.07;const needsExtraSpacing=graphInfo.range[X][MIN]>=0||isRelativelyCloseToZero;let paddingRequiredForTickLabels=0;if(needsExtraSpacing){const maxDigits=calculateMaxDigitsInRange(graphInfo.range[Y],tickStep[Y]);paddingRequiredForTickLabels=maxDigits*(fontSize*.75)+(graphInfo.range[Y][MIN]<0&&graphInfo.range[X][MIN]<=0?fontSize*.5:0);}const yAxisLabelOffset=[-14*1.25-paddingRequiredForTickLabels,-14];const xAxisLabelLocation=[(graphInfo.range[X][MIN]+graphInfo.range[X][MAX])/2,graphInfo.range[Y][MIN]];const yAxisLabelLocation=[graphInfo.range[X][MIN],(graphInfo.range[Y][MIN]+graphInfo.range[Y][MAX])/2];if(isRelativelyCloseToZero){yAxisLabelLocation[X]=yAxisLabelLocation[X]-graphInfo.range[X][MIN];}const xLabel=vec.add(pointToPixel(xAxisLabelLocation,graphInfo),xAxisLabelOffset);const yLabel=vec.add(pointToPixel(yAxisLabelLocation,graphInfo),yAxisLabelOffset);return [xLabel,yLabel]}const xLabelInitial=[graphInfo.range[X][MAX],0];const yLabelInitial=[0,graphInfo.range[Y][MAX]];const yLabelOffset=[0,-14*2];let xLabel=pointToPixel(xLabelInitial,graphInfo);let yLabel=vec.add(pointToPixel(yLabelInitial,graphInfo),yLabelOffset);xLabel=clampLabelPosition(xLabel,graphInfo);yLabel=clampLabelPosition(yLabel,graphInfo);return [xLabel,yLabel]};const shouldShowLabel=(currentTick,range,tickStep)=>{let showLabel=true;if(range[X][MIN]<-tickStep&&range[X][MAX]>0&¤tTick===-tickStep){showLabel=false;}return showLabel};function generateTickLocations(tickStep,min,max){const ticks=[];const decimalSigFigs=countSignificantDecimals(tickStep);const start=Math.max(min,0);for(let i=start+tickStep;i<max;i+=tickStep){ticks.push(parseFloat(i.toFixed(decimalSigFigs)));}let i=Math.min(max,0)-tickStep;for(i;i>min;i-=tickStep){ticks.push(i);}return ticks}const countSignificantDecimals=number=>{const numStr=number.toString();if(!numStr.includes(".")){return 0}return numStr.split(".")[1].length};function divideByAndShowPi(value){const dividedValue=value/Math.PI;switch(dividedValue){case 1:return "π";case -1:return "-π";case 0:return "0";default:return dividedValue+"π"}}
|
|
1876
1876
|
|
|
1877
|
-
|
|
1877
|
+
function AxisLabels({i18n}){const{range,labels,width,height,labelLocation,tickStep}=useGraphConfig();const graphInfo={range,width,height};const[xAxisLabelLocation,yAxisLabelLocation]=getLabelPosition(graphInfo,labelLocation,tickStep);const[xAxisLabelText,yAxisLabelText]=labels;const{xLabelTransform,yLabelTransform}=getLabelTransform(labelLocation);const{TeX}=getDependencies();return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("span",{"aria-hidden":true,style:{position:"absolute",left:xAxisLabelLocation[X],top:xAxisLabelLocation[Y],fontSize:fontSize+"px",transform:xLabelTransform},children:jsxRuntimeExports.jsx(TeX,{children:replaceOutsideTeX(xAxisLabelText)})}),jsxRuntimeExports.jsx("span",{"aria-hidden":true,style:{position:"absolute",left:yAxisLabelLocation[X],top:yAxisLabelLocation[Y],fontSize:fontSize+"px",transform:yLabelTransform},children:jsxRuntimeExports.jsx(TeX,{children:replaceOutsideTeX(yAxisLabelText)})})]})}
|
|
1878
|
+
|
|
1879
|
+
const tickSize=10;const tickLabelSize=14;const YGridTick=({y,range,tickStep,showPi})=>{let xPointOnAxis=0;if(range[X][MIN]>0){xPointOnAxis=range[X][MIN];}if(range[X][MAX]<0){xPointOnAxis=range[X][MAX];}const pointOnAxis=[xPointOnAxis,y];const[[xPosition,yPosition]]=useTransformVectorsToPixels(pointOnAxis);const x1=xPosition-tickSize/2;const y1=yPosition;const x2=xPosition+tickSize/2;const y2=yPosition;const xAdjustment=range[X][MAX]<=0?tickLabelSize*1.5:-14*1.1;const xPositionText=xPosition+xAdjustment;const yPositionText=yPosition+tickLabelSize*.25;const showLabel=shouldShowLabel(y,range,tickStep);const yLabel=showPi?divideByAndShowPi(y):y.toString();return jsxRuntimeExports.jsxs("g",{className:"tick","aria-hidden":true,children:[jsxRuntimeExports.jsx("line",{x1:x1,y1:y1,x2:x2,y2:y2,className:"axis-tick"}),showLabel&&jsxRuntimeExports.jsx("text",{className:"axis-tick-label",style:{fontSize:tickLabelSize},textAnchor:"end",x:xPositionText,y:yPositionText,children:yLabel})]})};const XGridTick=({x,range,showPi})=>{let yPointOnAxis=0;if(range[Y][MIN]>0){yPointOnAxis=range[Y][MIN];}if(range[Y][MAX]<0){yPointOnAxis=range[Y][MAX];}const pointOnAxis=[x,yPointOnAxis];const[[xPosition,yPosition]]=useTransformVectorsToPixels(pointOnAxis);const x1=xPosition;const y1=yPosition+tickSize/2;const x2=xPosition;const y2=yPosition-tickSize/2;const yAdjustment=range[Y][MAX]<0?-14:tickLabelSize*1.75;const xAdjustment=x<0?-2:0;const xPositionText=xPosition+xAdjustment;const yPositionText=yPosition+yAdjustment;const xLabel=showPi?divideByAndShowPi(x):x.toString();return jsxRuntimeExports.jsxs("g",{className:"tick","aria-hidden":true,children:[jsxRuntimeExports.jsx("line",{x1:x1,y1:y1,x2:x2,y2:y2,className:"axis-tick"}),jsxRuntimeExports.jsx("text",{className:"axis-tick-label",style:{fontSize:tickLabelSize},textAnchor:"middle",x:xPositionText,y:yPositionText,children:xLabel})]})};const AxisTicks=()=>{const{tickStep,range}=useGraphConfig();const[[xMin,xMax],[yMin,yMax]]=range;const[xTickStep,yTickStep]=tickStep;const yGridTicks=generateTickLocations(yTickStep,yMin,yMax);const xGridTicks=generateTickLocations(xTickStep,xMin,xMax);return jsxRuntimeExports.jsxs("g",{className:"axis-ticks",role:"presentation",children:[jsxRuntimeExports.jsx("g",{className:"y-axis-ticks",children:yGridTicks.map(y=>{return jsxRuntimeExports.jsx(YGridTick,{y:y,range:range,tickStep:tickStep[Y],showPi:tickStep[Y]%Math.PI===0},`y-grid-tick-${y}`)})}),jsxRuntimeExports.jsx("g",{className:"x-axis-ticks",children:xGridTicks.map(x=>{return jsxRuntimeExports.jsx(XGridTick,{x:x,range:range,showPi:tickStep[X]%Math.PI===0},`x-grid-tick-${x}`)})})]})};
|
|
1878
1880
|
|
|
1879
1881
|
const axisOptions=(props,axisIndex)=>{const lines=props.markings==="axes"?false:props.gridStep[axisIndex];return {axis:props.markings==="graph"||props.markings==="axes",lines:lines,labels:false}};const Grid=props=>{return props.markings==="none"?null:jsxRuntimeExports.jsx(Coordinates.Cartesian,{xAxis:axisOptions(props,X),yAxis:axisOptions(props,Y)})};
|
|
1880
1882
|
|
|
@@ -1917,27 +1919,27 @@ function LockedLabel(props){const{coord,text,color,size}=props;const[x,y]=pointT
|
|
|
1917
1919
|
|
|
1918
1920
|
function GraphLockedLabelsLayer(props){const{lockedFigures}=props;return lockedFigures.map((figure,i)=>{if(figure.type==="label"){return jsxRuntimeExports.jsx(LockedLabel,{...figure},`label-${i}`)}return jsxRuntimeExports.jsxs(React.Fragment,{children:[figure.labels.map((label,j)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`${i}-label-${j}`)),figure.type==="line"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[figure.points[0].labels.map((label,k)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`locked-figure-${i}-point-1-label-${k}`)),figure.points[1].labels.map((label,k)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`locked-figure-${i}-point-2-label-${k}`))]})]},i)})}
|
|
1919
1921
|
|
|
1920
|
-
const LockedEllipse=props=>{const{center,radius,angle,color: color$1,fillStyle,strokeStyle,ariaLabel}=props;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-ellipse","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Ellipse,{center:center,radius:radius,angle:angle,fillOpacity:lockedFigureFillStyles[fillStyle],strokeStyle:strokeStyle,color:lockedFigureColors[color$1],svgEllipseProps:{style:{fill:fillStyle==="white"?color.white:lockedFigureColors[color$1]}}})})};
|
|
1921
|
-
|
|
1922
1922
|
const strokeWeights={thin:1,medium:2,thick:4};function clampDomain(domain,graphBounds){if(domain[0]>domain[1]){return graphBounds}if(domain[0]<graphBounds[0]&&domain[1]<graphBounds[0]||domain[0]>graphBounds[1]&&domain[1]>graphBounds[1]){return null}const min=Math.max(domain[0],graphBounds[0]);const max=Math.min(domain[1],graphBounds[1]);return [min,max]}
|
|
1923
1923
|
|
|
1924
|
-
const
|
|
1924
|
+
const LockedEllipse=props=>{const{center,radius,angle,color: color$1,fillStyle,strokeStyle,weight,ariaLabel}=props;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-ellipse","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Ellipse,{center:center,radius:radius,angle:angle,fillOpacity:lockedFigureFillStyles[fillStyle],strokeStyle:strokeStyle,color:lockedFigureColors[color$1],weight:strokeWeights[weight],svgEllipseProps:{style:{fill:fillStyle==="white"?color.white:lockedFigureColors[color$1]}}})})};
|
|
1925
|
+
|
|
1926
|
+
const LockedFunction=props=>{const{range}=useGraphConfig();const[equation,setEquation]=useState();const{color,strokeStyle,weight,directionalAxis,domain}=props;const plotProps={color:lockedFigureColors[color],style:strokeStyle,weight:strokeWeights[weight]};const hasAria=!!props.ariaLabel;useEffect(()=>{setEquation(KAS.parse(props.equation).expr);},[props.equation]);if(typeof equation==="undefined"){return null}const clampedDomain=directionalAxis==="x"?clampDomain(domain,range[0]):clampDomain(domain,range[1]);if(clampedDomain===null){return null}return jsxRuntimeExports.jsxs("g",{className:"locked-function","aria-label":hasAria?props.ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:[directionalAxis==="x"&&jsxRuntimeExports.jsx(Plot$2.OfX,{y:x=>equation.eval({x}),domain:clampedDomain,...plotProps}),directionalAxis==="y"&&jsxRuntimeExports.jsx(Plot$2.OfY,{x:y=>equation.eval({y}),domain:clampedDomain,...plotProps})]})};
|
|
1925
1927
|
|
|
1926
1928
|
function SVGLine(props){const{start,end,style,className,testId}=props;return jsxRuntimeExports.jsx("line",{"aria-hidden":true,x1:start[X],y1:start[Y],x2:end[X],y2:end[Y],style:style,className:className,"data-testid":testId})}
|
|
1927
1929
|
|
|
1928
|
-
const{calculateAngleInDegrees: calculateAngleInDegrees$3}=angles;function Vector(props){const{interactiveColor}=useGraphConfig();const{tail,tip,color=interactiveColor,style,testId}=props;const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const direction=vec.sub(tipPx,tailPx);const angle=calculateAngleInDegrees$3(direction);return jsxRuntimeExports.jsxs("g",{style:{stroke:color,strokeWidth
|
|
1930
|
+
const{calculateAngleInDegrees: calculateAngleInDegrees$3}=angles;function Vector(props){const{interactiveColor}=useGraphConfig();const{tail,tip,color=interactiveColor,strokeWidth=2,style,testId}=props;const[tailPx,tipPx]=useTransformVectorsToPixels(tail,tip);const direction=vec.sub(tipPx,tailPx);const angle=calculateAngleInDegrees$3(direction);return jsxRuntimeExports.jsxs("g",{style:{stroke:color,strokeWidth},"data-testid":testId,children:[jsxRuntimeExports.jsx(SVGLine,{start:tailPx,end:tipPx,style:style}),jsxRuntimeExports.jsx(Arrowhead,{angle:angle,tip:tip,color:color,strokeWidth:strokeWidth})]})}
|
|
1929
1931
|
|
|
1930
1932
|
function srFormatNumber(a,locale,maximumFractionDigits){const piBasedNumber=getPiMultiple(a);if(piBasedNumber){return piBasedNumber}return (0+a).toLocaleString(locale,{maximumFractionDigits:maximumFractionDigits??3,useGrouping:false})}function getPiMultiple(a){if(Number.isInteger(a)||a===0||a>1e12){return null}const piCoefficient=a/Math.PI;const truncatedCoefficient=parseFloat(piCoefficient.toFixed(12));if(Number.isInteger(truncatedCoefficient)){return truncatedCoefficient+"π"}const acceptableDivisors=[2,3,4,6];for(const divisor of acceptableDivisors){const coefficientNumerator=parseFloat((piCoefficient*divisor).toFixed(12));if(Number.isInteger(coefficientNumerator)){return coefficientNumerator+"π/"+divisor}}return null}
|
|
1931
1933
|
|
|
1932
1934
|
const getIntersectionOfRayWithBox=(initialPoint,throughPoint,box)=>{const[[xMin,xMax],[yMin,yMax]]=box;const[aX,aY]=initialPoint;const[bX,bY]=throughPoint;const yDiff=bY-aY;const xDiff=bX-aX;const slope=yDiff/xDiff;const inverseSlope=1/slope;const xExtreme=xDiff<0?xMin:xMax;const yExtreme=yDiff<0?yMin:yMax;const yAtXExtreme=aY+(xExtreme-aX)*slope;const xAtYExtreme=aX+(yExtreme-aY)*inverseSlope;switch(true){case isBetween(yAtXExtreme,yMin,yMax):return [xExtreme,yAtXExtreme];case isBetween(xAtYExtreme,xMin,xMax):return [xAtYExtreme,yExtreme];default:return [xExtreme,yExtreme]}};function isBetween(x,low,high){return x>=low&&x<=high}function getArrayWithoutDuplicates(array){const returnArray=[];for(const coordPair of array){if(!returnArray.some(([x,y])=>x===coordPair[0]&&y===coordPair[1])){returnArray.push(coordPair);}}return returnArray}function getSlopeStringForLine(line,strings){const slope=(line[1][1]-line[0][1])/(line[1][0]-line[0][0]);if(!Number.isFinite(slope)){return strings.srLinearGraphSlopeVertical}if(slope===0){return strings.srLinearGraphSlopeHorizontal}return slope>0?strings.srLinearGraphSlopeIncreasing:strings.srLinearGraphSlopeDecreasing}function getInterceptStringForLine(line,strings,locale){const slope=(line[1][1]-line[0][1])/(line[1][0]-line[0][0]);const xIntercept=(0-line[0][1])/slope+line[0][0];const yIntercept=line[0][1]-slope*line[0][0];const overlapsXAxis=line[0][1]===0&&line[1][1]===0;const overlapsYAxis=line[0][0]===0&&line[1][0]===0;const hasXIntercept=Number.isFinite(xIntercept)&&!overlapsXAxis;const hasYIntercept=Number.isFinite(yIntercept)&&!overlapsYAxis;if(hasXIntercept&&hasYIntercept){return xIntercept===0&&yIntercept===0?strings.srLinearGraphOriginIntercept:strings.srLinearGraphBothIntercepts({xIntercept:srFormatNumber(xIntercept,locale),yIntercept:srFormatNumber(yIntercept,locale)})}return hasXIntercept?strings.srLinearGraphXOnlyIntercept({xIntercept:srFormatNumber(xIntercept,locale)}):strings.srLinearGraphYOnlyIntercept({yIntercept:srFormatNumber(yIntercept,locale)})}function getCoordQuadrant(coord){const[unroundedX,unroundedY]=coord;const x=Number(unroundedX.toFixed(3));const y=Number(unroundedY.toFixed(3));if(x===0&&y===0){return "origin"}if(y===0){return "x-axis"}if(x===0){return "y-axis"}if(x>0&&y>0){return 1}if(x<0&&y>0){return 2}if(x<0&&y<0){return 3}return 4}function getQuadraticVertexString(vertex,strings){const location=getCoordQuadrant(vertex);switch(location){case "origin":return strings.srQuadraticGraphVertexOrigin;case "x-axis":return strings.srQuadraticGraphVertexXAxis;case "y-axis":return strings.srQuadraticGraphVertexYAxis;default:return strings.srQuadraticGraphVertexQuadrant({quadrant:location})}}function getQuadraticPointString(pointNumber,coord,strings,locale){const location=getCoordQuadrant(coord);const[x,y]=coord;switch(location){case "origin":return strings.srQuadraticPointOrigin({pointNumber:pointNumber});case "x-axis":case "y-axis":return strings.srQuadraticPointAxis({pointNumber:pointNumber,x:srFormatNumber(x,locale),y:srFormatNumber(y,locale)});default:return strings.srQuadraticPointQuadrant({pointNumber:pointNumber,quadrant:location,x:srFormatNumber(x,locale),y:srFormatNumber(y,locale)})}}function getQuadraticXIntercepts(a,b,c){if(a===0){if(b===0){return []}return [-c/b]}const discriminant=b*b-4*a*c;if(discriminant<0){return []}const x1=(-b+Math.sqrt(discriminant))/(2*a);const x2=(-b-Math.sqrt(discriminant))/(2*a);if(x1===x2){return [x1]}return [x1,x2]}function getAngleFromPoints(points,i){if(i<0||i>=points.length||!Number.isInteger(i)){return null}if(points.length<3){return null}const point=points.at(i);const pt1=points.at(i-1);const pt2=points[(i+1)%points.length];if(!point||!pt1||!pt2){return null}const a=vec.dist(point,pt1);const b=vec.dist(point,pt2);const c=vec.dist(pt1,pt2);let lawOfCosinesRadicand=(a**2+b**2-c**2)/(2*a*b);if(lawOfCosinesRadicand<-1||lawOfCosinesRadicand>1){lawOfCosinesRadicand=Math.round(lawOfCosinesRadicand);}const angle=Math.acos(lawOfCosinesRadicand);return angle}function getSideLengthsFromPoints(points,i,isPolygonOpen){if(i<0||i>=points.length||!Number.isInteger(i)){return []}if(points.length<2){return []}const returnArray=[];const point=points[i];const point1Index=i===0?points.length-1:i-1;const point1=points[point1Index];const side1=i!==point1Index?vec.dist(point,point1):null;if(side1&&!(isPolygonOpen&&i===0)){returnArray.push({pointIndex:point1Index,sideLength:side1});}const point2Index=(i+1)%points.length;const point2=points[point2Index];const side2=i!==point2Index&&point2Index!==point1Index?vec.dist(point,point2):null;if(side2&&!(isPolygonOpen&&i===points.length-1)){returnArray.push({pointIndex:point2Index,sideLength:side2});}return returnArray}function getPolygonSideString(sideLength,pointIndex,strings,locale){return Number.isInteger(sideLength)?strings.srPolygonSideLength({pointNum:pointIndex+1,length:`${sideLength}`}):strings.srPolygonSideLengthApprox({pointNum:pointIndex+1,length:srFormatNumber(sideLength,locale,1)})}
|
|
1933
1935
|
|
|
1934
|
-
const{calculateAngleInDegrees: calculateAngleInDegrees$2}=angles;const LockedLine=props=>{const{color: color$1,lineStyle,kind,points,showPoint1,showPoint2,ariaLabel,range}=props;const[point1,point2]=points;const hasAria=!!ariaLabel;let line;if(kind==="ray"){const extendedPoint=getIntersectionOfRayWithBox(point1.coord,point2.coord,range);line=jsxRuntimeExports.jsx(Vector,{tail:point1.coord,tip:extendedPoint,color:lockedFigureColors[color$1],style:{strokeDasharray:lineStyle==="dashed"?"var(--mafs-line-stroke-dash-style)":undefined}});}else {const LineType=kind==="segment"?Line$4.Segment:Line$4.ThroughPoints;let arrowTip=kind==="segment"?point2.coord:getIntersectionOfRayWithBox(point1.coord,point2.coord,range);const[tailPx,tipPx]=useTransformVectorsToPixels(point2.coord,point1.coord);const direction=vec.sub(tailPx,tipPx);let angle=calculateAngleInDegrees$2(direction);const startArrowHead=kind!=="segment"&&jsxRuntimeExports.jsx(Arrowhead,{angle:angle,tip:arrowTip,color:lockedFigureColors[color$1]});arrowTip=kind==="segment"?point1.coord:getIntersectionOfRayWithBox(point2.coord,point1.coord,range);angle=angle>180?angle-180:angle+180;const endArrowHead=kind!=="segment"&&jsxRuntimeExports.jsx(Arrowhead,{angle:angle,tip:arrowTip,color:lockedFigureColors[color$1]});line=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[startArrowHead,jsxRuntimeExports.jsx(LineType,{point1:point1.coord,point2:point2.coord,color:lockedFigureColors[color$1],style:lineStyle}),endArrowHead]});}return jsxRuntimeExports.jsxs("g",{className:kind==="ray"?"locked-ray":"locked-line","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:[line,showPoint1&&jsxRuntimeExports.jsx(Point$2,{x:point1.coord[X],y:point1.coord[Y],svgCircleProps:{style:{fill:point1.filled?lockedFigureColors[point1.color]:color.white,stroke:lockedFigureColors[point1.color],strokeWidth:spacing.xxxxSmall_2}}}),showPoint2&&jsxRuntimeExports.jsx(Point$2,{x:point2.coord[X],y:point2.coord[Y],svgCircleProps:{style:{fill:point2.filled?lockedFigureColors[point2.color]:color.white,stroke:lockedFigureColors[point2.color],strokeWidth:spacing.xxxxSmall_2}}})]})};
|
|
1936
|
+
const{calculateAngleInDegrees: calculateAngleInDegrees$2}=angles;const LockedLine=props=>{const{color: color$1,lineStyle,kind,points,showPoint1,showPoint2,weight,ariaLabel,range}=props;const[point1,point2]=points;const hasAria=!!ariaLabel;let line;if(kind==="ray"){const extendedPoint=getIntersectionOfRayWithBox(point1.coord,point2.coord,range);line=jsxRuntimeExports.jsx(Vector,{tail:point1.coord,tip:extendedPoint,color:lockedFigureColors[color$1],strokeWidth:strokeWeights[weight],style:{strokeDasharray:lineStyle==="dashed"?"var(--mafs-line-stroke-dash-style)":undefined}});}else {const LineType=kind==="segment"?Line$4.Segment:Line$4.ThroughPoints;let arrowTip=kind==="segment"?point2.coord:getIntersectionOfRayWithBox(point1.coord,point2.coord,range);const[tailPx,tipPx]=useTransformVectorsToPixels(point2.coord,point1.coord);const direction=vec.sub(tailPx,tipPx);let angle=calculateAngleInDegrees$2(direction);const startArrowHead=kind!=="segment"&&jsxRuntimeExports.jsx(Arrowhead,{angle:angle,tip:arrowTip,color:lockedFigureColors[color$1],strokeWidth:strokeWeights[weight]});arrowTip=kind==="segment"?point1.coord:getIntersectionOfRayWithBox(point2.coord,point1.coord,range);angle=angle>180?angle-180:angle+180;const endArrowHead=kind!=="segment"&&jsxRuntimeExports.jsx(Arrowhead,{angle:angle,tip:arrowTip,color:lockedFigureColors[color$1],strokeWidth:strokeWeights[weight]});line=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[startArrowHead,jsxRuntimeExports.jsx(LineType,{point1:point1.coord,point2:point2.coord,color:lockedFigureColors[color$1],weight:strokeWeights[weight],style:lineStyle}),endArrowHead]});}return jsxRuntimeExports.jsxs("g",{className:kind==="ray"?"locked-ray":"locked-line","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:[line,showPoint1&&jsxRuntimeExports.jsx(Point$2,{x:point1.coord[X],y:point1.coord[Y],svgCircleProps:{style:{fill:point1.filled?lockedFigureColors[point1.color]:color.white,stroke:lockedFigureColors[point1.color],strokeWidth:spacing.xxxxSmall_2}}}),showPoint2&&jsxRuntimeExports.jsx(Point$2,{x:point2.coord[X],y:point2.coord[Y],svgCircleProps:{style:{fill:point2.filled?lockedFigureColors[point2.color]:color.white,stroke:lockedFigureColors[point2.color],strokeWidth:spacing.xxxxSmall_2}}})]})};
|
|
1935
1937
|
|
|
1936
1938
|
const LockedPoint=props=>{const{color: color$1,coord,filled,ariaLabel}=props;const[x,y]=coord;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-point","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Point$2,{x:x,y:y,svgCircleProps:{style:{fill:filled?lockedFigureColors[color$1]:color.white,stroke:lockedFigureColors[color$1],strokeWidth:spacing.xxxxSmall_2}}})})};
|
|
1937
1939
|
|
|
1938
|
-
const LockedPolygon=props=>{const{points,color: color$1,showVertices,fillStyle,strokeStyle,weight
|
|
1940
|
+
const LockedPolygon=props=>{const{points,color: color$1,showVertices,fillStyle,strokeStyle,weight}=props;const hasAria=!!props.ariaLabel;return jsxRuntimeExports.jsxs("g",{className:"locked-polygon","aria-label":hasAria?props.ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:[jsxRuntimeExports.jsx(Polygon,{points:[...points],fillOpacity:lockedFigureFillStyles[fillStyle],strokeStyle:strokeStyle,color:lockedFigureColors[color$1],weight:strokeWeights[weight],svgPolygonProps:{style:{fill:fillStyle==="white"?color.white:lockedFigureColors[color$1]}}}),showVertices&&points.map((point,index)=>jsxRuntimeExports.jsx(Point$2,{x:point[X],y:point[Y],color:lockedFigureColors[color$1]},`locked-polygon-point-${index}`))]})};
|
|
1939
1941
|
|
|
1940
|
-
const LockedVector=props=>{const{color,points,ariaLabel}=props;const[tail,tip]=points;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-vector","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Vector,{tail:tail,tip:tip,color:lockedFigureColors[color]})})};
|
|
1942
|
+
const LockedVector=props=>{const{color,points,weight,ariaLabel}=props;const[tail,tip]=points;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-vector","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Vector,{tail:tail,tip:tip,color:lockedFigureColors[color],strokeWidth:strokeWeights[weight]})})};
|
|
1941
1943
|
|
|
1942
1944
|
const GraphLockedLayer=props=>{const{lockedFigures}=props;return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:lockedFigures.map((figure,index)=>{switch(figure.type){case "point":return jsxRuntimeExports.jsx(LockedPoint,{...figure},`point-${index}`);case "line":return jsxRuntimeExports.jsx(LockedLine,{range:props.range,...figure},`line-${index}`);case "vector":return jsxRuntimeExports.jsx(LockedVector,{...figure},`vector-${index}`);case "ellipse":return jsxRuntimeExports.jsx(LockedEllipse,{...figure},`ellipse-${index}`);case "polygon":return jsxRuntimeExports.jsx(LockedPolygon,{...figure},`polygon-${index}`);case "function":return jsxRuntimeExports.jsx(LockedFunction,{...figure},`function-${index}`);case "label":return null;default:throw new UnreachableCaseError(figure)}})})};
|
|
1943
1945
|
|
|
@@ -1991,7 +1993,7 @@ function renderSinusoidGraph(state,dispatch,i18n){return {graph:jsxRuntimeExport
|
|
|
1991
1993
|
|
|
1992
1994
|
const{calculateAngleInDegrees,convertDegreesToRadians}=angles;const protractorImage="https://cdn.kastatic.org/images/perseus/protractor.svg";const centerToTopLeft=[-195,-190];const centerToRotationHandle=[-201,-15];function Protractor(){const staticUrl=getDependencies().staticUrl;const{range,snapStep}=useGraphConfig();const[[xMin,xMax],[yMin,yMax]]=range;const initialCenter=[lerp(xMin,xMax,.5),lerp(yMin,yMax,.25)];const[center,setCenter]=useState(initialCenter);const[rotationHandleOffset,setRotationHandleOffset]=useState(centerToRotationHandle);const draggableRef=useRef(null);const{dragging}=useDraggable({gestureTarget:draggableRef,onMove:setCenter,point:center,constrainKeyboardMovement:point=>bound$1({snapStep,range,point})});const rotationHandleRef=useRef(null);useDraggablePx({gestureTarget:rotationHandleRef,onMove:setRotationHandleOffset,point:rotationHandleOffset,constrain:constrainToCircle});const[centerPx]=useTransformVectorsToPixels(center);const topLeftPx=vec.add(centerPx,centerToTopLeft);const angle=calculateAngleInDegrees(rotationHandleOffset)-calculateAngleInDegrees(centerToRotationHandle);return jsxRuntimeExports.jsxs("g",{ref:draggableRef,transform:`translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,style:{transformOrigin:`${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,cursor:dragging?"grabbing":"grab"},children:[jsxRuntimeExports.jsx("image",{href:staticUrl(protractorImage)}),jsxRuntimeExports.jsx("g",{transform:`translate(5, ${-centerToTopLeft[1]})`,ref:rotationHandleRef,children:jsxRuntimeExports.jsx(RotationArrow,{})})]})}function RotationArrow(){const radius=175;const angleDeg=10;const angleRad=convertDegreesToRadians(angleDeg);const endX=radius*(1-Math.cos(angleRad));const endY=radius*-Math.sin(angleRad);const rotationArrow=pathBuilder().move(0,0).circularArc(radius,endX,endY,{sweep:true}).build();const arrowhead=pathBuilder().move(-8,0).line(0,10).line(8,0).build();const targetRadius=TARGET_SIZE/2;return jsxRuntimeExports.jsxs("g",{className:"protractor-rotation-handle",children:[jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrow-arc",d:rotationArrow}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead,transform:`translate(${endX}, ${endY}), rotate(${180+angleDeg})`}),jsxRuntimeExports.jsx("ellipse",{cx:"0px",cy:"-15px",rx:targetRadius,ry:targetRadius,fill:"none"})]})}const protractorRadius=vec.mag(centerToRotationHandle);function constrainToCircle(edgePoint){return vec.withMag(edgePoint,protractorRadius)}function useDraggablePx(args){const{gestureTarget:target,onMove,point,constrain=p=>p}=args;const pickupPx=React.useRef([0,0]);useDrag(state=>{const{event,first,movement:pixelMovement}=state;event?.stopPropagation();if(first){pickupPx.current=point;}if(vec.mag(pixelMovement)===0){return}onMove?.(constrain(vec.add(pickupPx.current,pixelMovement)));},{target,eventOptions:{passive:false}});}
|
|
1993
1995
|
|
|
1994
|
-
const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React.useRef(null);const{analytics}=useDependencies();const{viewboxX,viewboxY}=calculateNestedSVGCoords(state.range,width,height);const viewBox=`${viewboxX} ${viewboxY} ${width} ${height}`;const nestedSVGAttributes={width,height,viewBox,preserveAspectRatio:"xMidYMin",x:viewboxX,y:viewboxY};const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:interactive-graph-widget:rendered",payload:{type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:"20px",marginBottom:"30px",pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId,state.type!=="none"&&!disableInteraction&&instructionsId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[fullGraphAriaDescription&&jsxRuntimeExports.jsx(View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n})}),jsxRuntimeExports.jsx(View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures.length>0&&jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:jsxRuntimeExports.jsxs("svg",{...nestedSVGAttributes,children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:"white",border:"1px solid #21242C52",padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(LabelMedium,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const getRangeDiff=range=>{const[min,max]=range;return Math.abs(max-min)};const calculateNestedSVGCoords=(range,width,height)=>{let viewboxX=0;const totalXRange=getRangeDiff(range[X]);const gridCellWidth=width/totalXRange;const minX=range[X][MIN];if(minX>0){viewboxX=gridCellWidth*Math.abs(minX);}if(minX<0){viewboxX=-gridCellWidth*Math.abs(minX);}let viewboxY=-height;const totalYRange=getRangeDiff(range[Y]);const gridCellHeight=height/totalYRange;const minY=range[Y][MIN];if(minY>0){viewboxY=-height-gridCellHeight*Math.abs(minY);}if(minY<0){viewboxY=gridCellHeight*Math.abs(minY)-height;}return {viewboxX,viewboxY}};const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};default:throw new UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
1996
|
+
const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React.useRef(null);const{analytics}=useDependencies();const{viewboxX,viewboxY}=calculateNestedSVGCoords(state.range,width,height);const viewBox=`${viewboxX} ${viewboxY} ${width} ${height}`;const nestedSVGAttributes={width,height,viewBox,preserveAspectRatio:"xMidYMin",x:viewboxX,y:viewboxY};const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:interactive-graph-widget:rendered",payload:{type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:"20px",marginBottom:"30px",pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId,state.type!=="none"&&!disableInteraction&&instructionsId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[fullGraphAriaDescription&&jsxRuntimeExports.jsx(View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n})}),jsxRuntimeExports.jsx(View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures.length>0&&jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:jsxRuntimeExports.jsxs("svg",{...nestedSVGAttributes,children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:"white",border:"1px solid #21242C52",padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(LabelMedium,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};default:throw new UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
1995
1997
|
|
|
1996
1998
|
function mafsStateToInteractiveGraph(state,originalGraph){switch(state.type){case "angle":invariant(originalGraph.type==="angle");return {...originalGraph,coords:state.coords};case "quadratic":invariant(originalGraph.type==="quadratic");return {...originalGraph,coords:state.coords};case "circle":invariant(originalGraph.type==="circle");return {...originalGraph,center:state.center,radius:getRadius(state)};case "linear":invariant(originalGraph.type==="linear");return {...originalGraph,coords:state.coords};case "ray":invariant(originalGraph.type==="ray");return {...originalGraph,coords:state.coords};case "sinusoid":invariant(originalGraph.type==="sinusoid");return {...originalGraph,coords:state.coords};case "segment":invariant(originalGraph.type==="segment");return {...originalGraph,coords:state.coords};case "linear-system":invariant(originalGraph.type==="linear-system");return {...originalGraph,coords:state.coords};case "polygon":invariant(originalGraph.type==="polygon");return {...originalGraph,coords:state.coords};case "point":invariant(originalGraph.type==="point");return {...originalGraph,coords:state.coords};case "none":invariant(originalGraph.type==="none");return {...originalGraph};default:throw new UnreachableCaseError(state)}}
|
|
1997
1999
|
|
|
@@ -2073,7 +2075,7 @@ var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,D
|
|
|
2073
2075
|
|
|
2074
2076
|
const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
|
|
2075
2077
|
|
|
2076
|
-
const libName="@khanacademy/perseus";const libVersion="65.
|
|
2078
|
+
const libName="@khanacademy/perseus";const libVersion="65.6.0";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
2077
2079
|
|
|
2078
2080
|
const apiVersion={major:12,minor:0};
|
|
2079
2081
|
|