@khanacademy/perseus-editor 40.0.3 → 41.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/scrollless-number-text-field.d.ts +14 -3
- package/dist/es/index.js +12 -12
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +11 -12
- package/dist/index.js.map +1 -1
- package/dist/util/midpoint.d.ts +2 -0
- package/package.json +6 -6
- package/dist/iframe-content-renderer.d.ts +0 -23
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { TextField } from "@khanacademy/wonder-blocks-form";
|
|
2
1
|
import * as React from "react";
|
|
3
|
-
import type {
|
|
2
|
+
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
|
+
interface Props {
|
|
4
|
+
value: number;
|
|
5
|
+
onChange: (value: number) => void;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
10
|
+
onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
|
|
11
|
+
style?: StyleType;
|
|
12
|
+
}
|
|
4
13
|
/**
|
|
5
14
|
* This is a custom text field of type="number" for use in Perseus Editors.
|
|
6
15
|
*
|
|
@@ -12,6 +21,8 @@ import type { PropsFor } from "@khanacademy/wonder-blocks-core";
|
|
|
12
21
|
* events. This is useful to make sure that input behavior
|
|
13
22
|
* remains predictable, rather than possibly having the cursor
|
|
14
23
|
* jump around uenxpectedly.
|
|
24
|
+
* 3. only valid, finite numbers are passed to `onChange`. NaN and +/-Infinity
|
|
25
|
+
* are never emitted.
|
|
15
26
|
*
|
|
16
27
|
* NOTE 1: Native HTML number inputs do not update the number value on scroll,
|
|
17
28
|
* they only scroll the page. Inputs in React do NOT work this way (explanation
|
|
@@ -23,5 +34,5 @@ import type { PropsFor } from "@khanacademy/wonder-blocks-core";
|
|
|
23
34
|
* NOTE 2: Firefox seems to have a custom override for input scroll. Even
|
|
24
35
|
* with this stopPropogation, Firefox matches the native HTML behavior.
|
|
25
36
|
*/
|
|
26
|
-
declare const ScrolllessNumberTextField: (props:
|
|
37
|
+
declare const ScrolllessNumberTextField: (props: Props) => React.JSX.Element;
|
|
27
38
|
export default ScrolllessNumberTextField;
|
package/dist/es/index.js
CHANGED
|
@@ -67,7 +67,7 @@ import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
|
|
|
67
67
|
import arrowDown from '@phosphor-icons/core/regular/arrow-down.svg';
|
|
68
68
|
import arrowUp from '@phosphor-icons/core/regular/arrow-up.svg';
|
|
69
69
|
|
|
70
|
-
const libName="@khanacademy/perseus-editor";const libVersion="
|
|
70
|
+
const libName="@khanacademy/perseus-editor";const libVersion="41.0.0";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
71
71
|
|
|
72
72
|
var jsxRuntime = {exports: {}};
|
|
73
73
|
|
|
@@ -1529,8 +1529,6 @@ function lintRenderer(content,widgets){const parsed=PerseusMarkdown.parse(conten
|
|
|
1529
1529
|
|
|
1530
1530
|
const{HUD}=components;class EditorPage extends React.Component{componentDidMount(){this.setState({issues:gatherLinterIssues(this.props.question,this.props.hints,this.props.issues)});}getSnapshotBeforeUpdate(prevProps){if(!prevProps.jsonMode&&this.props.jsonMode){return this.itemEditor.current?.serialize()??{}}return null}componentDidUpdate(previousProps,prevState,snapshot){if(snapshot){this.setState({json:snapshot});return}if(!_.isEqual(previousProps.question,this.props.question)||!_.isEqual(previousProps.answerArea,this.props.answerArea)||!_.isEqual(previousProps.hints,this.props.hints)){this.syncJsonStateFromProps();}const questionOrHintsChanged=previousProps.question?.content!==this.props.question?.content||previousProps.question?.widgets!==this.props.question?.widgets||!_.isEqual(previousProps.hints,this.props.hints);if(questionOrHintsChanged){this.setState({issues:gatherLinterIssues(this.props.question,this.props.hints,this.props.issues)});}}syncJsonStateFromProps(){this.setState({json:{question:this.props.question,answerArea:this.props.answerArea,hints:this.props.hints}});}getSaveWarnings(){return this.itemEditor.current?.getSaveWarnings()}serialize(){if(this.props.jsonMode){return this.state.json}invariant(this.itemEditor.current,"cannot serialize EditorPage without ItemEditor");return this.itemEditor.current.serialize()}render(){let className="framework-perseus";const editingDisabled=this.props.apiOptions?.editingDisabled??false;const touch=this.props.previewDevice==="phone"||this.props.previewDevice==="tablet";const deviceBasedApiOptions=this.deriveDeviceApiOptions({apiOptions:this.props.apiOptions,touch});const showEditor=!this.props.developerMode||!this.props.jsonMode;if(deviceBasedApiOptions.isMobile){className+=" "+ClassNames.MOBILE;}return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsx(ItemEditorContext.Provider,{value:{question:this.props.question,onEditorChange:this.handleEditorChange,editingDisabled:this.props.apiOptions?.editingDisabled},children:jsxRuntimeExports.jsxs("div",{id:"perseus",className:className,children:[jsxRuntimeExports.jsxs("div",{style:{marginBlockEnd:10},children:[this.props.developerMode&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Developer JSON Mode:"," ",jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.jsonMode,disabled:this.props.apiOptions?.editingDisabled,onChange:this.toggleJsonMode})]})," "]}),!this.props.jsonMode&&jsxRuntimeExports.jsx(ViewportResizer,{deviceType:this.props.previewDevice,onViewportSizeChanged:this.props.onPreviewDeviceChange}),!this.props.jsonMode&&jsxRuntimeExports.jsx(HUD,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})]}),this.props.developerMode&&this.props.jsonMode&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,value:this.state.json,parser:parseAndMigratePerseusItem,onChange:this.changeJSON,editingDisabled:editingDisabled})}),jsxRuntimeExports.jsxs(A11yContext.Provider,{value:createA11yContextValue({setIssueHighlight:this.setIssueHighlight,a11yScanningEnabled:this.state.a11yScanningEnabled,setA11yScanningEnabled:this.setA11yScanningEnabled,highlightInstanceIds:this.state.highlightInstanceIds,onA11yReport:this.handleA11yReport,axeCoreIssues:this.state.axeCoreIssues}),children:[showEditor&&jsxRuntimeExports.jsx("div",{className:"perseus-editor-table",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(IssuesPanel,{issues:this.state.issues})})})}),showEditor&&jsxRuntimeExports.jsx(ItemEditor,{ref:this.itemEditor,itemId:this.props.itemId,question:this.props.question,hints:this.props.hints,answerArea:this.props.answerArea,imageUploader:this.props.imageUploader,onChange:this.handleChange,deviceType:this.props.previewDevice,widgetIsOpen:this.state.widgetsAreOpen,apiOptions:deviceBasedApiOptions,previewURL:this.props.previewURL,additionalTemplates:this.props.additionalTemplates,highlightLint:this.state.highlightLint,problemNum:this.props.problemNum})]})]})})})}constructor(props){super(props),this.itemEditor=React.createRef(),this.deriveDeviceApiOptions=createDeviceApiOptionsDeriver(),this.setIssueHighlight=(instanceId,highlighted)=>{this.setState(prevState=>{const current=prevState.highlightInstanceIds;if(highlighted===current.includes(instanceId)){return null}return {highlightInstanceIds:highlighted?[...current,instanceId]:current.filter(id=>id!==instanceId)}});},this.handleA11yReport=report=>{this.setState({axeCoreIssues:report?[...report.violations,...report.needsReview]:[]});},this.setA11yScanningEnabled=enabled=>{this.setState({a11yScanningEnabled:enabled});},this.toggleJsonMode=()=>{this.setState({json:this.serialize()},()=>{this.props.onChange({jsonMode:!this.props.jsonMode});});},this.handleChange=toChange=>{const newProps=_(this.props).pick("question","hints","answerArea");_(newProps).extend(toChange);this.props.onChange(newProps);},this.handleEditorChange=newProps=>{this.handleChange({question:{...this.props.question,...newProps}});},this.changeJSON=newJson=>{this.setState({json:newJson});this.props.onChange(newJson);};this.state={json:_.pick(this.props,"question","answerArea","hints"),highlightLint:true,widgetsAreOpen:this.props.widgetsAreOpen??true,issues:[],axeCoreIssues:[],a11yScanningEnabled:false,highlightInstanceIds:[]};}}EditorPage.defaultProps={answerArea:getDefaultAnswerArea(),developerMode:false,hints:[],jsonMode:false,onChange:()=>{}};
|
|
1531
1531
|
|
|
1532
|
-
let nextIframeID=0;const requestIframeData={};const updateIframeHeight={};window.iframeDataStore={};window.addEventListener("message",event=>{if(typeof event.data==="string"){const callback=requestIframeData[event.data];if(callback){callback();}}else if(event.data.id){if(event.data.height!==undefined){updateIframeHeight[event.data.id](event.data.height);}else if(event.data.lintWarnings){Log.log("LINTER REPORT",{lintWarnings:JSON.stringify(event.data.lintWarnings)});}}});class IframeContentRenderer extends React.Component{componentDidMount(){this._isMounted=true;this.iframeID=nextIframeID;nextIframeID++;this._prepareFrame();requestIframeData[this.iframeID]=()=>{this.sendNewData(this._lastData);};updateIframeHeight[this.iframeID]=height=>{this._lastHeight=height;if(this._isMounted&&this.props.seamless&&this.container.current){this.container.current.style.height=height+"px";}};}shouldComponentUpdate(nextProps){return nextProps.datasetValue!==this.props.datasetValue||nextProps.seamless!==this.props.seamless}componentDidUpdate(prevProps){if(this.container.current){if(!this.props.seamless){this.container.current.style.height="100%";}else {this.container.current.style.height=this._lastHeight+"px";}}if(prevProps.datasetValue!==this.props.datasetValue){this._prepareFrame();}}componentWillUnmount(){requestIframeData[this.iframeID]=null;updateIframeHeight[this.iframeID]=null;this._isMounted=false;}_prepareFrame(){if(this._frame){this.container.current?.removeChild(this._frame);}const frame=document.createElement("iframe");frame.style.width="100%";frame.style.height="100%";frame.dataset.name="content-preview";frame.src=this.props.url;frame.onload=()=>{const iframeDoc=frame.contentDocument||frame.contentWindow?.document;if(iframeDoc){const axeCoreScriptElement=iframeDoc.createElement("script");axeCoreScriptElement.src="https://unpkg.com/axe-core@4.11.0/axe.js";iframeDoc.body.appendChild(axeCoreScriptElement);}else {console.warn("Unable to add axe-core to iframe document");}};if(this.props.datasetKey){frame.dataset[this.props.datasetKey]=this.props.datasetValue;}frame.dataset.id=String(this.iframeID);if(this.props.seamless){frame.dataset.lintGutter="true";}this.container.current?.appendChild(frame);this._frame=frame;}sendNewData(data){const frame=this._frame;if(this._isMounted&&data&&frame?.contentWindow){this._lastData=data;window.iframeDataStore[this.iframeID]=data;frame.contentWindow.postMessage(this.iframeID,"*");}}render(){return jsxRuntimeExports.jsx("div",{ref:this.container,style:{width:"100%",height:"100%"}})}constructor(...args){super(...args),this.container=React.createRef();}}
|
|
1533
|
-
|
|
1534
1532
|
function ContentPreview({question,apiOptions,seamless,linterContext,legacyPerseusLint,previewDevice,reviewMode}){const i18n=usePerseusI18n();const isMobile=previewDevice!=="desktop";const className=isMobile?"perseus-mobile":"";return jsxRuntimeExports.jsx(View,{className:`framework-perseus ${className}`,style:[styles$P.container,!seamless?styles$P.gutter:undefined],children:jsxRuntimeExports.jsx(StatefulKeypadContextProvider,{children:jsxRuntimeExports.jsx(KeypadContext.Consumer,{children:({setKeypadActive,keypadElement,setKeypadElement})=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(UserInputManager,{widgets:question?.widgets||{},problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{strings:i18n.strings,apiOptions:{...apiOptions,isMobile},keypadElement:keypadElement,linterContext:linterContext,legacyPerseusLint:legacyPerseusLint,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,reviewMode:reviewMode,...question})}),jsxRuntimeExports.jsx(MobileKeypad,{onAnalyticsEvent:()=>Promise.resolve(),onDismiss:()=>setKeypadActive(false),onElementMounted:setKeypadElement})]})})})})}const styles$P=StyleSheet.create({container:{padding:spacing.xxxSmall_4,containerType:"inline-size",containerName:"perseus-root"},gutter:{marginInlineEnd:lintGutterWidth}});
|
|
1535
1533
|
|
|
1536
1534
|
var issuesList = {"axe-core":{"user-fixable":["aria-input-field-name","aria-meter-name","aria-toggle-field-name","image-alt","input-image-alt","label","link-name","list","role-img-alt","select-name","summary-name","svg-img-alt","video-caption"]}};
|
|
@@ -1596,9 +1594,9 @@ var styles$J = {"decorativeToggleContainer":"perseus_Z9--Lqsc","flexRow":"perseu
|
|
|
1596
1594
|
|
|
1597
1595
|
function DecorativeToggle({decorative,hasPopulatedFields,editingDisabled=false,onChange}){function handleDecorativeToggle(newValue){if(!newValue){onChange({decorative:false});return}if(!hasPopulatedFields){onChange({decorative:true});return}const shouldReset=window.confirm("Setting this image as decorative will automatically reset all other fields (title, caption, alt text, and long description). Do you want to continue?");if(shouldReset){onChange({decorative:true,alt:"",caption:undefined,title:undefined,longDescription:undefined});}}return jsxRuntimeExports.jsx("div",{className:styles$J.decorativeToggleContainer,children:jsxRuntimeExports.jsxs("div",{className:styles$J.flexRow,children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Decorative",checked:decorative??false,disabled:editingDisabled,onChange:handleDecorativeToggle}),jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"Mark this image as decorative and it will not have any alt text, description, title, or caption."})})]})})}
|
|
1598
1596
|
|
|
1599
|
-
const ScrolllessNumberTextField=props=>{const{value,onChange,...restOfProps}=props;const[focused,setFocused]=React.useState(false);const[wipValue,setWipValue]=React.useState("");const inputRef=React.useRef(null);React.useEffect(()=>{const ref=inputRef.current;const ignoreScroll=e=>{e.stopPropagation();};ref?.addEventListener("wheel",ignoreScroll);return ()=>{ref?.removeEventListener("wheel",ignoreScroll);}},[inputRef]);return jsxRuntimeExports.jsx(TextField,{...restOfProps,type:"number",value:focused?wipValue:value,onChange:newValue=>{setWipValue(newValue);onChange(newValue);},onFocus:e=>{setWipValue(value);setFocused(true);props.onFocus?.(e);},onBlur:e=>{setFocused(false);props.onBlur?.(e);},ref:inputRef})};
|
|
1597
|
+
const ScrolllessNumberTextField=props=>{const{value,onChange,...restOfProps}=props;const[focused,setFocused]=React.useState(false);const[wipValue,setWipValue]=React.useState("");const inputRef=React.useRef(null);React.useEffect(()=>{const ref=inputRef.current;const ignoreScroll=e=>{e.stopPropagation();};ref?.addEventListener("wheel",ignoreScroll);return ()=>{ref?.removeEventListener("wheel",ignoreScroll);}},[inputRef]);return jsxRuntimeExports.jsx(TextField,{...restOfProps,type:"number",value:focused?wipValue:String(value),onChange:newValue=>{setWipValue(newValue);if(isFiniteNumeric(newValue)){onChange(+newValue);}},onFocus:e=>{setWipValue(String(value));setFocused(true);props.onFocus?.(e);},onBlur:e=>{setFocused(false);props.onBlur?.(e);},ref:inputRef})};function isFiniteNumeric(value){return value.trim()!==""&&Number.isFinite(+value)}
|
|
1600
1598
|
|
|
1601
|
-
const LARGE_DIMENSION_THRESHOLD=1048576;function ImageScaleInput({backgroundImage,scale,editingDisabled=false,onChange}){const width=backgroundImage.width??0;const height=backgroundImage.height??0;const hasInvalidDimensions=isInvalidDimension(width)||isInvalidDimension(height);function handleScaleChange(newScale){
|
|
1599
|
+
const LARGE_DIMENSION_THRESHOLD=1048576;function ImageScaleInput({backgroundImage,scale,editingDisabled=false,onChange}){const width=backgroundImage.width??0;const height=backgroundImage.height??0;const hasInvalidDimensions=isInvalidDimension(width)||isInvalidDimension(height);function handleScaleChange(newScale){if(newScale<=0){return}onChange({scale:newScale});}function handleScaledWidthChange(newScaledWidth){if(newScaledWidth<=0){return}if(width===0){return}onChange({scale:newScaledWidth/width});}function handleScaledHeightChange(newScaledHeight){if(newScaledHeight<=0){return}if(height===0){return}onChange({scale:newScaledHeight/height});}async function handleResetToOriginalSize(){if(!backgroundImage.url){return}const naturalSize=await Util.getImageSizeModern(backgroundImage.url);const[naturalWidth,naturalHeight]=naturalSize;if(naturalWidth===backgroundImage.width&&naturalHeight===backgroundImage.height){return}onChange({backgroundImage:{...backgroundImage,width:naturalWidth,height:naturalHeight}});}const hasLargeDimensions=width*height>LARGE_DIMENSION_THRESHOLD;return jsxRuntimeExports.jsxs("div",{className:styles$L.dimensionsContainer,children:[jsxRuntimeExports.jsxs(BodyMonospace,{children:["Natural size: ",width," x ",height]}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",size:"small",startIcon:arrowCounterClockwise,disabled:editingDisabled,onClick:handleResetToOriginalSize,children:"Recalculate natural size"}),hasLargeDimensions&&jsxRuntimeExports.jsx(Banner,{kind:"warning",text:"Large images may cause slow performance for learners. Please use a max size of 1024 x 1024."}),jsxRuntimeExports.jsx("div",{className:styles$L.horizontalLine}),hasInvalidDimensions&&jsxRuntimeExports.jsx(Banner,{kind:"warning",text:'Image size is invalid. Please use the "Recalculate natural size" button to enable scaling.',styles:{root:{marginBottom:sizing.size_080}}}),jsxRuntimeExports.jsx(LabeledField,{label:"Scale",description:"Use 1 to display image at original size.",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:scale,min:0,onChange:handleScaleChange,disabled:hasInvalidDimensions||editingDisabled}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$L.dimensionsFieldContainer,children:[jsxRuntimeExports.jsx(LabeledField,{label:"Scaled Width",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:width*scale,min:0,onChange:handleScaledWidthChange,disabled:hasInvalidDimensions||editingDisabled}),styles:wbFieldStyles}),jsxRuntimeExports.jsx("span",{className:styles$L.xSpan,children:"x"}),jsxRuntimeExports.jsx(LabeledField,{label:"Scaled Height",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:height*scale,min:0,onChange:handleScaledHeightChange,disabled:hasInvalidDimensions||editingDisabled}),styles:wbFieldStyles})]})]})}
|
|
1602
1600
|
|
|
1603
1601
|
const MIN_ALT_TEXT_LENGTH=8;const MAX_ALT_TEXT_LENGTH=125;const altTextTooLongError="Keep alt succinct at roughly 125 characters in length. Please pair the alt with a long description if you need significantly more text to sufficiently describe the image.";const altTextTooShortError="Add more detail to describe your image. While alt text should be brief, it must also describe the image well.";function ImageSettings({alt,apiOptions,backgroundImage,scale=1,caption,decorative,longDescription,title,onChange}){const[altFieldWarning,setAltFieldWarning]=React.useState(null);const[wbTheme,setWBTheme]=React.useState(undefined);if(!backgroundImage.url){return null}const editingDisabled=apiOptions?.editingDisabled??false;const hasPopulatedFields=Boolean(alt||caption||title||longDescription);function handleAltFieldChange(value){if(value.length===0){setAltFieldWarning(null);}else if(value.length>MAX_ALT_TEXT_LENGTH){setAltFieldWarning(altTextTooLongError);}else if(value.length>=MIN_ALT_TEXT_LENGTH){setAltFieldWarning(null);}onChange({alt:value});}function handleAltFieldBlur(value){if(value.length>0&&value.length<MIN_ALT_TEXT_LENGTH){setAltFieldWarning(altTextTooShortError);}}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Preview",field:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(DarkModeToggle,{editingDisabled:editingDisabled,backgroundImage:backgroundImage,onShowToggle:setWBTheme,onSuppressToggle:onChange}),jsxRuntimeExports.jsx(ImagePreview,{src:backgroundImage.url,alt:`Preview: ${alt||"No alt text"}`,width:backgroundImage.width,height:backgroundImage.height,wbTheme:wbTheme})]}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(ImageScaleInput,{backgroundImage:backgroundImage,scale:scale,editingDisabled:editingDisabled,onChange:onChange}),jsxRuntimeExports.jsx(DecorativeToggle,{decorative:decorative,hasPopulatedFields:hasPopulatedFields,editingDisabled:editingDisabled,onChange:onChange}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(TextArea,{value:title??"",onChange:value=>onChange({title:value}),disabled:decorative||editingDisabled,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$L.altTextFieldContainer,children:[jsxRuntimeExports.jsx(LabeledField,{label:"Alt text",description:"Summarize the image using up to 125 characters.",field:jsxRuntimeExports.jsx(TextArea,{value:alt??"",onBlur:e=>handleAltFieldBlur(e.target.value),onChange:handleAltFieldChange,disabled:decorative||editingDisabled,autoResize:true}),styles:wbFieldStylesWithDescription}),jsxRuntimeExports.jsxs(BodyText,{size:"xsmall",tag:"span",style:wbStyles.characterCounter,children:[alt?.length??0," characters"]})]}),altFieldWarning&&jsxRuntimeExports.jsx(Banner,{kind:"warning",text:altFieldWarning,styles:{root:{marginBottom:sizing.size_080}}}),jsxRuntimeExports.jsx(LabeledField,{label:"Long description",field:jsxRuntimeExports.jsx(TextArea,{value:longDescription??"",onChange:value=>onChange({longDescription:value}),disabled:decorative||editingDisabled,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(TextArea,{value:caption??"",onChange:value=>onChange({caption:value}),disabled:decorative||editingDisabled,autoResize:true}),styles:wbFieldStyles})]})}const wbStyles=StyleSheet.create({characterCounter:{position:"absolute",insetBlockEnd:0,insetInlineEnd:8}});
|
|
1604
1602
|
|
|
@@ -1692,11 +1690,11 @@ var styles$y = {"container":"perseus_UMms5ska","addElementSelect":"perseus_Dz9XA
|
|
|
1692
1690
|
|
|
1693
1691
|
const LockedFigureSelect=props=>{const{id,editingDisabled,onChange}=props;const figureTypes=["point","line","vector","ellipse","polygon","function","label"];return jsxRuntimeExports.jsx(View,{className:styles$y.container,children:jsxRuntimeExports.jsx(ActionMenu,{menuText:"Add locked figure",disabled:editingDisabled,className:styles$y.addElementSelect,children:figureTypes.map(figureType=>jsxRuntimeExports.jsx(ActionItem,{label:figureType,onClick:()=>onChange(figureType)},`${id}-${figureType}`))})})};
|
|
1694
1692
|
|
|
1695
|
-
const{convertDegreesToRadians,convertRadiansToDegrees: convertRadiansToDegrees$1}=angles;const AngleInput=props=>{const{angle,onChange}=props;
|
|
1693
|
+
const{convertDegreesToRadians,convertRadiansToDegrees: convertRadiansToDegrees$1}=angles;const AngleInput=props=>{const{angle,onChange}=props;function handleAngleChange(newValue){onChange(convertDegreesToRadians(newValue));}return jsxRuntimeExports.jsxs(BodyText,{tag:"label",style:styles$x.row,children:["angle (degrees)",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:convertRadiansToDegrees$1(angle),onChange:handleAngleChange,style:styles$x.textField}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6})]})};const styles$x=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
|
|
1696
1694
|
|
|
1697
1695
|
var styles$w = {"container":"perseus_6kPoH3-I","label":"perseus_qYirPY7G"};
|
|
1698
1696
|
|
|
1699
|
-
const textFieldStyle={width:sizing.size_640};const errorFieldStyle={borderColor:semanticColor.core.border.critical.default,backgroundColor:semanticColor.core.background.critical.subtle};const CoordinatePairInput=props=>{const{coord,labels,error,style,labelClassName,disabled=false,onChange}=props;const xLabel=labels?labels[0]:"x coord";const yLabel=labels?labels[1]:"y coord";
|
|
1697
|
+
const textFieldStyle={width:sizing.size_640};const errorFieldStyle={borderColor:semanticColor.core.border.critical.default,backgroundColor:semanticColor.core.background.critical.subtle};const CoordinatePairInput=props=>{const{coord,labels,error,style,labelClassName,disabled=false,onChange}=props;const xLabel=labels?labels[0]:"x coord";const yLabel=labels?labels[1]:"y coord";function handleCoordChange(newValue,coordIndex){const newCoords=[...coord];newCoords[coordIndex]=newValue;onChange(newCoords);}return jsxRuntimeExports.jsxs(View,{className:styles$w.container,style:style,children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",className:styles$w.label,children:[jsxRuntimeExports.jsx("span",{className:labelClassName,children:xLabel}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coord[0],disabled:disabled,onChange:newValue=>handleCoordChange(newValue,0),style:[textFieldStyle,error?errorFieldStyle:undefined]})]}),jsxRuntimeExports.jsxs(BodyText,{tag:"label",className:styles$w.label,children:[jsxRuntimeExports.jsx("span",{className:labelClassName,children:yLabel}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:coord[1],disabled:disabled,onChange:newValue=>handleCoordChange(newValue,1),style:[textFieldStyle,error?errorFieldStyle:undefined]})]})]})};
|
|
1700
1698
|
|
|
1701
1699
|
var styles$v = {"row":"perseus_v9IBfM--"};
|
|
1702
1700
|
|
|
@@ -1740,6 +1738,8 @@ var styles$l = {"accordionHeader":"perseus_tXEvWJUz","axisMenu":"perseus_3xCRJZP
|
|
|
1740
1738
|
|
|
1741
1739
|
const LockedFunctionSettings=props=>{const{color:lineColor,strokeStyle,equation,directionalAxis,domain,weight,ariaLabel,editingDisabled=false,onChangeProps,onMove,onRemove}=props;const labels=props.labels;const equationPrefix=directionalAxis==="x"?"y=":"x=";const lineLabel=`Function (${equationPrefix}${equation})`;const getDomainStringValues=domain=>{return [Number.isFinite(domain[0])?domain[0].toString():"",Number.isFinite(domain[1])?domain[1].toString():""]};const[domainEntries,setDomainEntries]=useState(getDomainStringValues(domain));const[exampleCategory,setExampleCategory]=useState(null);useEffect(()=>{setDomainEntries(getDomainStringValues(domain));},[domain]);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);let str=`Function${visiblelabel} with equation ${equationPrefix}${equation}`;if(Number.isFinite(domain[0])||Number.isFinite(domain[1])){str+=`, domain from ${domain[0]} to ${domain[1]}`;}const functionAppearance=generateLockedFigureAppearanceDescription(lineColor,strokeStyle,undefined,weight);str+=functionAppearance;return str}function handlePropChange(property,newValue){const updatedProps={};updatedProps[property]=newValue;onChangeProps(updatedProps);}function handleDomainChange(limitIndex,newValueString){const newDomainEntries=[...domainEntries];newDomainEntries[limitIndex]=newValueString;setDomainEntries(newDomainEntries);const newDomain=[...domain];let newValue=parseFloat(newValueString);if(newValueString===""&&limitIndex===0){newValue=-Infinity;}else if(newValueString===""&&limitIndex===1){newValue=Infinity;}newDomain[limitIndex]=newValue;onChangeProps({domain:newDomain});}const exampleContent=exampleCategory!=null?examples[exampleCategory]:["Select category to see example equations"];function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{className:`${styles$l.row} ${styles$l.header}`,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",className:styles$l.accordionHeader,children:lineLabel}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{className:`${styles$l.row} ${styles$l.colorRow}`,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,editingDisabled:editingDisabled,onChange:handleColorChange}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,options:lineStrokeStyleOptions,editingDisabled:editingDisabled,onChange:newValue=>{handlePropChange("strokeStyle",newValue);}})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,editingDisabled:editingDisabled,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsxs(View,{className:`${styles$l.row} ${styles$l.rowSpace} ${styles$l.axisRow}`,children:[jsxRuntimeExports.jsx(TypedSingleSelect,{selectedValue:directionalAxis,disabled:editingDisabled,options:{x:"y =",y:"x ="},onChange:newValue=>{handlePropChange("directionalAxis",newValue);},"aria-label":"equation prefix",className:`${styles$l.dropdownLabel} ${styles$l.axisMenu}`}),jsxRuntimeExports.jsx(TextField,{type:"text","aria-label":"equation",value:equation,disabled:editingDisabled,onChange:newValue=>{handlePropChange("equation",newValue);},style:{flexGrow:1}})]}),jsxRuntimeExports.jsxs(View,{className:`${styles$l.row} ${styles$l.rowSpace} ${styles$l.domainRow}`,children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",className:`${styles$l.dropdownLabel} ${styles$l.domainMin}`,children:["domain min",jsxRuntimeExports.jsx(TextField,{type:"number",style:{width:"calc(100% - 88.7px)"},value:domainEntries[0],disabled:editingDisabled,onChange:newValue=>{handleDomainChange(0,newValue);}})]}),jsxRuntimeExports.jsxs(BodyText,{tag:"label","aria-label":"domain max",className:`${styles$l.dropdownLabel} ${styles$l.domainMax}`,children:["max",jsxRuntimeExports.jsx(TextField,{type:"number",style:{width:"calc(100% - 36.2px)"},value:domainEntries[1],disabled:editingDisabled,onChange:newValue=>{handleDomainChange(1,newValue);}})]})]}),jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Example Functions"}),expanded:false,containerStyle:{background:semanticColor.core.background.base.subtle},panelStyle:{alignItems:"start",paddingBottom:sizing.size_120,flexDirection:"row",flexWrap:"wrap"},children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",className:styles$l.dropdownLabel,children:["Choose a category",jsxRuntimeExports.jsx(TypedSingleSelect,{selectedValue:exampleCategory,disabled:editingDisabled,options:{linear:"linear",polynomial:"polynomial",trigonometric:"trigonometric"},onChange:setExampleCategory,placeholder:"examples"})]}),exampleCategory!=null&&jsxRuntimeExports.jsx("ul",{className:styles$l.exampleContainer,children:exampleContent.map((example,index)=>jsxRuntimeExports.jsx(ExampleItem,{category:exampleCategory,example:example,index:index,editingDisabled:editingDisabled,pasteEquationFn:handlePropChange},index))})]}),jsxRuntimeExports.jsx(View,{className:`${styles$l.horizontalRule} ${styles$l.sectionTop}`}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,editingDisabled:editingDisabled,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(View,{className:`${styles$l.horizontalRule} ${styles$l.dividerTight}`}),jsxRuntimeExports.jsx(BodyText,{className:styles$l.sectionTop,children:"Visible labels"}),labels.map((label,labelIndex)=>jsxRuntimeExports.jsx(LockedLabelSettings,{...label,editingDisabled:editingDisabled,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:{backgroundColor:semanticColor.core.background.base.default}},labelIndex)),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,disabled:editingDisabled,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[0,-labels.length],color:lineColor};onChangeProps({labels:[...labels,newLabel]});},className:styles$l.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,editingDisabled:editingDisabled,onMove:onMove,onRemove:onRemove})]})};const ExampleItem=props=>{const{category,example,index,editingDisabled,pasteEquationFn}=props;const exampleId=useId();return jsxRuntimeExports.jsxs("li",{className:styles$l.exampleRow,children:[jsxRuntimeExports.jsx(IconButton,{icon:autoPasteIcon,kind:"tertiary","aria-label":"paste example","aria-describedby":exampleId,disabled:editingDisabled,onClick:()=>pasteEquationFn("equation",example),size:"medium",className:styles$l.copyPasteButton}),jsxRuntimeExports.jsx(IconButton,{icon:copyIcon,kind:"tertiary","aria-label":"copy example","aria-describedby":exampleId,disabled:editingDisabled,onClick:()=>navigator.clipboard.writeText(example),size:"medium",className:styles$l.copyPasteButton}),jsxRuntimeExports.jsx(View,{className:`${styles$l.exampleContent} ${styles$l.exampleContentIndent}`,id:exampleId,children:example})]},`${category}-${index}`)};
|
|
1742
1740
|
|
|
1741
|
+
function midpoint(p1,p2){return vec.scale(vec.add(p1,p2),.5)}
|
|
1742
|
+
|
|
1743
1743
|
var styles$k = {"row":"perseus_nBzKD32m","header":"perseus_WNElRLBL","spaceUnder":"perseus_sEXwoqeH","kindLabel":"perseus_MohIPkUC","colorRow":"perseus_WDC67hHF","errorText":"perseus_57zeueK9","addButton":"perseus_se9nOPo3","horizontalRule":"perseus_XnNJefSQ","sectionTop":"perseus_mCvSm-pU","dividerTight":"perseus_34Yfh9Ri"};
|
|
1744
1744
|
|
|
1745
1745
|
var styles$j = {"row":"perseus_PsQTUHiB","addButton":"perseus_DzebTj-c","horizontalRule":"perseus_pxo33u6Q","sectionTop":"perseus_pOW3mBVq","dividerTight":"perseus_iXTo2lsa"};
|
|
@@ -1747,7 +1747,7 @@ var styles$j = {"row":"perseus_PsQTUHiB","addButton":"perseus_DzebTj-c","horizon
|
|
|
1747
1747
|
const spaceUnderStyle$1={marginBottom:sizing.size_080};const LockedPointSettings=props=>{const{headerLabel,editingDisabled=false,coord,color:pointColor,filled=true,labels,ariaLabel,onChangeProps,onMove,onRemove,showPoint,error,expanded,onTogglePoint,onToggle}=props;const isDefiningPoint=!onMove&&!onRemove;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenX=await generateSpokenMathDetails(`$${coord[0]}$`);const spokenY=await generateSpokenMathDetails(`$${coord[1]}$`);let str=`Point${visiblelabel} at ${spokenX} comma ${spokenY}`;const pointAppearance=generateLockedFigureAppearanceDescription(pointColor,"solid",filled?undefined:"none");str+=pointAppearance;return str}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleCoordChange(newCoord){const xOffset=newCoord[0]-coord[0];const yOffset=newCoord[1]-coord[1];const newProps={coord:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,containerStyle:isDefiningPoint?{marginTop:sizing.size_080,marginBottom:0,marginLeft:-sizing.size_040,marginRight:-sizing.size_040,backgroundColor:semanticColor.core.background.base.default}:undefined,panelStyle:isDefiningPoint?{paddingBottom:sizing.size_060}:undefined,header:jsxRuntimeExports.jsxs(View,{className:styles$j.row,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:`${headerLabel||"Point"} (${coord[0]}, ${coord[1]})`}),jsxRuntimeExports.jsx(ColorSwatch,{color:pointColor,filled:filled})]}),children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,style:spaceUnderStyle$1,disabled:editingDisabled,onChange:handleCoordChange,error:!!error}),onTogglePoint&&jsxRuntimeExports.jsx(LabeledSwitch,{label:"show point on graph",checked:!!showPoint,style:showPoint&&spaceUnderStyle$1,disabled:editingDisabled,onChange:onTogglePoint}),(!isDefiningPoint||showPoint)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:pointColor,onChange:handleColorChange,style:spaceUnderStyle$1,editingDisabled:editingDisabled}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"open point",checked:!filled,disabled:editingDisabled,onChange:newValue=>{onChangeProps({filled:!newValue});}})]}),!isDefiningPoint&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(View,{className:`${styles$j.horizontalRule} ${styles$j.sectionTop}`}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,editingDisabled:editingDisabled,onChangeProps:newProps=>{onChangeProps(newProps);}})]}),jsxRuntimeExports.jsx(View,{className:`${styles$j.horizontalRule} ${styles$j.dividerTight}`}),jsxRuntimeExports.jsx(BodyText,{className:styles$j.sectionTop,children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,editingDisabled:editingDisabled,containerStyle:!isDefiningPoint&&{backgroundColor:semanticColor.core.background.base.default},expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);}})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,disabled:editingDisabled,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[coord[0]+.5,coord[1]-labels.length],color:pointColor};onChangeProps({labels:[...labels,newLabel]});},className:styles$j.addButton,children:"Add visible label"}),onRemove&&jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,editingDisabled:editingDisabled,onMove:onMove,onRemove:onRemove})]})};
|
|
1748
1748
|
|
|
1749
1749
|
const lengthZeroStr="The line cannot have length 0.";const labelContainerStyle$2={backgroundColor:semanticColor.core.background.base.default};const LockedLineSettings=props=>{const{kind,points,color:lineColor,lineStyle="solid",showPoint1,showPoint2,weight,labels,ariaLabel,editingDisabled=false,onChangeProps,onMove,onRemove}=props;const[point1,point2]=points;const capitalizeKind=kind.charAt(0).toUpperCase()+kind.slice(1);const lineLabel=`${capitalizeKind} (${point1.coord[0]},
|
|
1750
|
-
${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;const isInvalid=vector.equal(point1.coord,point2.coord);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const point1VisibleLabel=await joinLabelsAsSpokenMath(point1.labels);const point2VisibleLabel=await joinLabelsAsSpokenMath(point2.labels);const spokenPoint1X=await generateSpokenMathDetails(`$${point1.coord[0]}$`);const spokenPoint1Y=await generateSpokenMathDetails(`$${point1.coord[1]}$`);const spokenPoint2X=await generateSpokenMathDetails(`$${point2.coord[0]}$`);const spokenPoint2Y=await generateSpokenMathDetails(`$${point2.coord[1]}$`);let str;switch(kind){case "line":str=`${capitalizeKind}${visiblelabel} through point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} and point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "ray":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} through point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "segment":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} to point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;default:throw new UnreachableCaseError(kind,"Unknown line kind")}const lineAppearance=generateLockedFigureAppearanceDescription(lineColor,lineStyle,undefined,weight);str+=lineAppearance;return str}function handleChangePoint(newPointProps,index){const newPoints=[...points];newPoints[index]={...points[index],...newPointProps};const oldMidpoint=
|
|
1750
|
+
${point1.coord[1]}), (${point2.coord[0]}, ${point2.coord[1]})`;const isInvalid=vector.equal(point1.coord,point2.coord);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const point1VisibleLabel=await joinLabelsAsSpokenMath(point1.labels);const point2VisibleLabel=await joinLabelsAsSpokenMath(point2.labels);const spokenPoint1X=await generateSpokenMathDetails(`$${point1.coord[0]}$`);const spokenPoint1Y=await generateSpokenMathDetails(`$${point1.coord[1]}$`);const spokenPoint2X=await generateSpokenMathDetails(`$${point2.coord[0]}$`);const spokenPoint2Y=await generateSpokenMathDetails(`$${point2.coord[1]}$`);let str;switch(kind){case "line":str=`${capitalizeKind}${visiblelabel} through point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} and point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "ray":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} through point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;case "segment":str=`${capitalizeKind}${visiblelabel} from point${point1VisibleLabel} at ${spokenPoint1X} comma ${spokenPoint1Y} to point${point2VisibleLabel} at ${spokenPoint2X} comma ${spokenPoint2Y}`;break;default:throw new UnreachableCaseError(kind,"Unknown line kind")}const lineAppearance=generateLockedFigureAppearanceDescription(lineColor,lineStyle,undefined,weight);str+=lineAppearance;return str}function handleChangePoint(newPointProps,index){const newPoints=[...points];newPoints[index]={...points[index],...newPointProps};const oldMidpoint=midpoint(points[0].coord,points[1].coord);const newMidpoint=midpoint(newPoints[0].coord,newPoints[1].coord);const offset=[newMidpoint[0]-oldMidpoint[0],newMidpoint[1]-oldMidpoint[1]];const newLabels=labels.map((label,labelIndex)=>({...label,coord:[label.coord[0]+offset[0],label.coord[1]+offset[1]]}));onChangeProps({points:newPoints,labels:newLabels});}function handleColorChange(newColor){const newLabels=labels.map(label=>({...label,color:newColor}));onChangeProps({color:newColor,points:[{...point1,color:newColor,labels:point1.labels.map(label=>({...label,color:newColor}))},{...point2,color:newColor,labels:point2.labels.map(label=>({...label,color:newColor}))}],labels:newLabels});}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{className:`${styles$k.row} ${styles$k.header}`,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:lineLabel}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:lineStyle})]}),children:[jsxRuntimeExports.jsxs(BodyText,{tag:"label",className:`${styles$k.row} ${styles$k.spaceUnder} ${styles$k.kindLabel}`,children:["kind",jsxRuntimeExports.jsx(TypedSingleSelect,{selectedValue:kind,disabled:editingDisabled,onChange:value=>onChangeProps({kind:value}),options:{line:"line",ray:"ray",segment:"segment"}})]}),jsxRuntimeExports.jsxs(View,{className:`${styles$k.row} ${styles$k.spaceUnder} ${styles$k.colorRow}`,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,editingDisabled:editingDisabled,onChange:handleColorChange}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:lineStyle,options:lineStrokeStyleOptions,editingDisabled:editingDisabled,onChange:value=>onChangeProps({lineStyle:value})})]}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,editingDisabled:editingDisabled,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(BodyText,{className:styles$k.errorText,children:lengthZeroStr}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 1",expanded:true,showPoint:showPoint1,error:isInvalid?lengthZeroStr:null,...point1,editingDisabled:editingDisabled,onTogglePoint:newValue=>onChangeProps({showPoint1:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,0)}),jsxRuntimeExports.jsx(LockedPointSettings,{headerLabel:"Point 2",expanded:true,showPoint:showPoint2,error:isInvalid?lengthZeroStr:null,...point2,editingDisabled:editingDisabled,onTogglePoint:newValue=>onChangeProps({showPoint2:newValue}),onChangeProps:newProps=>handleChangePoint(newProps,1)}),jsxRuntimeExports.jsx(View,{className:`${styles$k.horizontalRule} ${styles$k.sectionTop}`}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,editingDisabled:editingDisabled,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(View,{className:`${styles$k.horizontalRule} ${styles$k.dividerTight}`}),jsxRuntimeExports.jsx(BodyText,{className:styles$k.sectionTop,children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,editingDisabled:editingDisabled,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:labelContainerStyle$2})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,disabled:editingDisabled,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),midpoint(points[0].coord,points[1].coord));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},className:styles$k.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,editingDisabled:editingDisabled,onMove:onMove,onRemove:onRemove})]})};
|
|
1751
1751
|
|
|
1752
1752
|
var styles$i = {"row":"perseus_7gvpLIxX","header":"perseus_a9dhxydf","spaceUnder":"perseus_FMC5CN4y","colorRow":"perseus_bj3iyVpL","fillLabel":"perseus_gbGj72Hu","icon":"perseus_DYnWU1Yr","polygonActionsContainer":"perseus_YhcLg4qs","movementButtonsContainer":"perseus_DtEDhGzL","truncatedWidth":"perseus_14L-Mr6p","addButton":"perseus_dc8k1hRY","horizontalRule":"perseus_iR-te9L8","sectionTop":"perseus_q3l-Nth6","dividerTight":"perseus_WNA-ZWQ8"};
|
|
1753
1753
|
|
|
@@ -1757,7 +1757,7 @@ const spaceUnderStyle={marginBottom:sizing.size_080};const pointAccordionContain
|
|
|
1757
1757
|
|
|
1758
1758
|
var styles$g = {"row":"perseus_Ug-lFL8r","errorText":"perseus_6gvwJ939","addButton":"perseus_vcxh5KIo","horizontalRule":"perseus_HRitDKmQ","sectionTop":"perseus_QY6CaDZH","dividerTight":"perseus_QDq7G5V4"};
|
|
1759
1759
|
|
|
1760
|
-
const lengthErrorMessage="The vector cannot have length 0.";const coordsAccordionContainerStyle={marginTop:sizing.size_080,marginBottom:0,marginLeft:-sizing.size_040,marginRight:-sizing.size_040,backgroundColor:semanticColor.core.background.base.default};const coordsAccordionPanelStyle={paddingBottom:sizing.size_160};const labelContainerStyle={backgroundColor:semanticColor.core.background.base.default};const LockedVectorSettings=props=>{const{points,color:lineColor,weight,labels,ariaLabel,editingDisabled=false,onChangeProps,onMove,onRemove}=props;const[tail,tip]=points;const lineLabel=`Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;const isInvalid=vector.equal(tail,tip);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenTailX=await generateSpokenMathDetails(`$${tail[0]}$`);const spokenTailY=await generateSpokenMathDetails(`$${tail[1]}$`);const spokenTipX=await generateSpokenMathDetails(`$${tip[0]}$`);const spokenTipY=await generateSpokenMathDetails(`$${tip[1]}$`);let str=`Vector${visiblelabel} from ${spokenTailX} comma ${spokenTailY} to ${spokenTipX} comma ${spokenTipY}`;const vectorAppearance=generateLockedFigureAppearanceDescription(lineColor,"solid",undefined,weight);str+=vectorAppearance;return str}function handleChangePoint(newCoord,index){if(typeof newCoord!=="undefined"){const newPoints=[...points];newPoints[index]=[...newCoord];const oldMidpoint=
|
|
1760
|
+
const lengthErrorMessage="The vector cannot have length 0.";const coordsAccordionContainerStyle={marginTop:sizing.size_080,marginBottom:0,marginLeft:-sizing.size_040,marginRight:-sizing.size_040,backgroundColor:semanticColor.core.background.base.default};const coordsAccordionPanelStyle={paddingBottom:sizing.size_160};const labelContainerStyle={backgroundColor:semanticColor.core.background.base.default};const LockedVectorSettings=props=>{const{points,color:lineColor,weight,labels,ariaLabel,editingDisabled=false,onChangeProps,onMove,onRemove}=props;const[tail,tip]=points;const lineLabel=`Vector (${tail[0]}, ${tail[1]}), (${tip[0]}, ${tip[1]})`;const isInvalid=vector.equal(tail,tip);async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenTailX=await generateSpokenMathDetails(`$${tail[0]}$`);const spokenTailY=await generateSpokenMathDetails(`$${tail[1]}$`);const spokenTipX=await generateSpokenMathDetails(`$${tip[0]}$`);const spokenTipY=await generateSpokenMathDetails(`$${tip[1]}$`);let str=`Vector${visiblelabel} from ${spokenTailX} comma ${spokenTailY} to ${spokenTipX} comma ${spokenTipY}`;const vectorAppearance=generateLockedFigureAppearanceDescription(lineColor,"solid",undefined,weight);str+=vectorAppearance;return str}function handleChangePoint(newCoord,index){if(typeof newCoord!=="undefined"){const newPoints=[...points];newPoints[index]=[...newCoord];const oldMidpoint=midpoint(tail,tip);const newMidpoint=midpoint(newPoints[0],newPoints[1]);const offset=vec.sub(newMidpoint,oldMidpoint);const newLabels=labels.map(label=>({...label,coord:vec.add(label.coord,offset)}));onChangeProps({points:newPoints,labels:newLabels});}}function handleColorChange(newColor){const newProps={color:newColor};newProps.labels=labels.map(label=>({...label,color:newColor}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:props.expanded,onToggle:props.onToggle,header:jsxRuntimeExports.jsxs(View,{className:styles$g.row,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:lineLabel}),jsxRuntimeExports.jsx(LineSwatch,{color:lineColor,lineStyle:"solid"})]}),children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:lineColor,editingDisabled:editingDisabled,onChange:handleColorChange,style:{marginBlockEnd:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,editingDisabled:editingDisabled,onChange:value=>onChangeProps({weight:value})}),isInvalid&&jsxRuntimeExports.jsx(BodyText,{className:styles$g.errorText,children:lengthErrorMessage}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:coordsAccordionContainerStyle,panelStyle:coordsAccordionPanelStyle,header:jsxRuntimeExports.jsx(View,{className:styles$g.row,children:jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:`Tail (${tail[0]}, ${tail[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tail,error:isInvalid,disabled:editingDisabled,onChange:newProps=>{handleChangePoint(newProps,0);}})}),jsxRuntimeExports.jsx(PerseusEditorAccordion,{expanded:true,containerStyle:coordsAccordionContainerStyle,panelStyle:coordsAccordionPanelStyle,header:jsxRuntimeExports.jsx(View,{className:styles$g.row,children:jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:`Tip (${tip[0]}, ${tip[1]})`})}),children:jsxRuntimeExports.jsx(CoordinatePairInput,{coord:tip,error:isInvalid,disabled:editingDisabled,onChange:newProps=>{handleChangePoint(newProps,1);}})}),jsxRuntimeExports.jsx(View,{className:`${styles$g.horizontalRule} ${styles$g.sectionTop}`}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,editingDisabled:editingDisabled,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(View,{className:`${styles$g.horizontalRule} ${styles$g.dividerTight}`}),jsxRuntimeExports.jsx(BodyText,{className:styles$g.sectionTop,children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,editingDisabled:editingDisabled,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:labelContainerStyle})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,disabled:editingDisabled,onClick:()=>{const offsetPerLabel=[0,-1];const labelLocation=vec.add(vec.scale(offsetPerLabel,labels.length),midpoint(tail,tip));const newLabel={...getDefaultFigureForType("label"),coord:labelLocation,color:lineColor};onChangeProps({labels:[...labels,newLabel]});},className:styles$g.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,editingDisabled:editingDisabled,onMove:onMove,onRemove:onRemove})]})};
|
|
1761
1761
|
|
|
1762
1762
|
const LockedFigureSettings=props=>{switch(props.type){case "point":return jsxRuntimeExports.jsx(LockedPointSettings,{...props});case "line":return jsxRuntimeExports.jsx(LockedLineSettings,{...props});case "vector":return jsxRuntimeExports.jsx(LockedVectorSettings,{...props});case "ellipse":return jsxRuntimeExports.jsx(LockedEllipseSettings,{...props});case "polygon":return jsxRuntimeExports.jsx(LockedPolygonSettings,{...props});case "function":return jsxRuntimeExports.jsx(LockedFunctionSettings,{...props});case "label":return jsxRuntimeExports.jsx(LockedLabelSettings,{...props});default:throw new UnreachableCaseError(props)}};
|
|
1763
1763
|
|
|
@@ -1775,9 +1775,9 @@ const{getClockwiseAngle}=angles;function getStartCoords(graph){if("startCoords"i
|
|
|
1775
1775
|
|
|
1776
1776
|
const StartCoordsAngle=props=>{const{startCoords,allowReflexAngles,onChange,pointLabels,onChangePointLabels}=props;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??"",index===2?newLabel:pointLabels[2]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$d.equationSection,children:[jsxRuntimeExports.jsx(BodyText,{children:"Starting equation:"}),jsxRuntimeExports.jsx(BodyMonospace,{style:styles$d.equationBody,children:getAngleEquation(startCoords,allowReflexAngles)})]}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:startCoords[0],onChange:value=>onChange([value,startCoords[1],startCoords[2]]),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Vertex",coord:startCoords[1],onChange:value=>onChange([startCoords[0],value,startCoords[2]]),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:startCoords[2],onChange:value=>onChange([startCoords[0],startCoords[1],value]),pointLabel:pointLabels[2],onPointLabelChange:newLabel=>updatePointLabel(2,newLabel)})]})};const styles$d=StyleSheet.create({equationSection:{marginBlockStart:spacing.small_12},equationBody:{backgroundColor:semanticColor.core.background.neutral.subtle,border:`1px solid ${semanticColor.core.border.neutral.subtle}`,marginBlockStart:spacing.xSmall_8,paddingInlineStart:spacing.xSmall_8,paddingInlineEnd:spacing.xSmall_8,fontSize:font.body.size.xsmall}});
|
|
1777
1777
|
|
|
1778
|
-
const StartCoordsCircle=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;
|
|
1778
|
+
const StartCoordsCircle=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;function handleRadiusChange(newValue){if(newValue===0){return}onChange({center:startCoords.center,radius:newValue});}return jsxRuntimeExports.jsxs(View,{style:styles$c.tile,children:[jsxRuntimeExports.jsxs(View,{style:styles$c.row,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Center:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords.center,labels:["x","y"],onChange:coord=>onChange({center:coord,radius:startCoords.radius})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(BodyText,{size:"medium",weight:"bold",tag:"label",style:styles$c.row,children:["Radius:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:startCoords.radius,onChange:handleRadiusChange,style:styles$c.textField})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(BodyText,{size:"medium",weight:"bold",tag:"span",style:styles$c.row,children:["Radius point label:",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$c.textField,children:jsxRuntimeExports.jsx(TextField,{"aria-label":"Radius point name",value:pointLabels[0]??"",placeholder:"Radius point",onChange:newLabel=>onChangePointLabels([newLabel])})})]})]})};const styles$c=StyleSheet.create({tile:{backgroundColor:semanticColor.core.background.instructive.subtle,marginBlockStart:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8},row:{display:"flex",flexDirection:"row",alignItems:"center"},textField:{width:spacing.xxxLarge_64}});
|
|
1779
1779
|
|
|
1780
|
-
const AsymptoteInput=props=>{const{axis,value,onChange}=props;
|
|
1780
|
+
const AsymptoteInput=props=>{const{axis,value,onChange}=props;function handleChange(newValue){onChange(newValue);}return jsxRuntimeExports.jsxs(BodyText,{weight:"bold",tag:"label",className:styles$e.tileRow,children:[`Asymptote ${axis} =`,jsxRuntimeExports.jsx(View,{className:styles$e["text-field-wrapper"],children:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:value,onChange:handleChange})})]})};
|
|
1781
1781
|
|
|
1782
1782
|
const StartCoordsExponential=props=>{const{startCoords,onChange,pointLabels,onChangePointLabels}=props;const{coords,asymptote}=startCoords;const updatePointLabel=(index,newLabel)=>{const next=[index===0?newLabel:pointLabels[0]??"",index===1?newLabel:pointLabels[1]??""];onChangePointLabels(next);};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(CoordInput,{label:"Point 1",coord:coords[0],onChange:value=>onChange({coords:[value,coords[1]],asymptote}),pointLabel:pointLabels[0],onPointLabelChange:newLabel=>updatePointLabel(0,newLabel)}),jsxRuntimeExports.jsx(CoordInput,{label:"Point 2",coord:coords[1],onChange:value=>onChange({coords:[coords[0],value],asymptote}),pointLabel:pointLabels[1],onPointLabelChange:newLabel=>updatePointLabel(1,newLabel)}),jsxRuntimeExports.jsx(AsymptoteInput,{axis:"y",value:asymptote,onChange:newY=>onChange({coords:[coords[0],coords[1]],asymptote:newY})})]})};
|
|
1783
1783
|
|
|
@@ -1883,5 +1883,5 @@ var AllEditors = {categorizer:CategorizerEditor,"cs-program":CSProgramEditor,def
|
|
|
1883
1883
|
|
|
1884
1884
|
Widgets.registerEditors(AllEditors);Widgets.registerWidgets(widgets);Widgets.replaceDeprecatedWidgets();Widgets.replaceDeprecatedEditors();
|
|
1885
1885
|
|
|
1886
|
-
export { A11yOverlays, AllEditors, ArticleDiff, ArticleEditor, ContentPreview, DeviceFramer, Editor, EditorPage,
|
|
1886
|
+
export { A11yOverlays, AllEditors, ArticleDiff, ArticleEditor, ContentPreview, DeviceFramer, Editor, EditorPage, IssuesPanel, ItemDiff, PreviewWithIframe, ViewportResizer, libVersion, usePreviewController, usePreviewPresenter };
|
|
1887
1887
|
//# sourceMappingURL=index.js.map
|