@khanacademy/perseus-editor 30.1.0 → 30.1.1

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.
@@ -13,8 +13,8 @@ declare class BlurInput extends React.Component<Props, State> {
13
13
  input: React.RefObject<HTMLInputElement>;
14
14
  constructor(props: Props);
15
15
  UNSAFE_componentWillReceiveProps(nextProps: Props): void;
16
- handleChange: (e: any) => void;
17
- handleBlur: (e: any) => void;
16
+ handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
17
+ handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void;
18
18
  focus(): void;
19
19
  render(): React.ReactNode;
20
20
  }
@@ -1,14 +1,12 @@
1
1
  import * as React from "react";
2
2
  type Props = {
3
- onDrop: (e: DragEvent) => void;
4
- component?: any;
5
- shouldDragHighlight: (any: any) => boolean;
6
- style?: any;
7
- children?: any;
3
+ onDrop: (e: React.MouseEvent) => unknown;
4
+ shouldDragHighlight: (e: React.MouseEvent) => boolean;
5
+ style?: React.CSSProperties;
6
+ children?: React.ReactNode;
8
7
  className?: string;
9
8
  };
10
9
  type DefaultProps = {
11
- component: Props["component"];
12
10
  shouldDragHighlight: Props["shouldDragHighlight"];
13
11
  };
14
12
  type State = {
@@ -16,12 +14,12 @@ type State = {
16
14
  };
17
15
  declare class DragTarget extends React.Component<Props, State> {
18
16
  static defaultProps: DefaultProps;
19
- constructor(props: any);
20
- handleDrop(e: DragEvent): void;
17
+ constructor(props: Props);
18
+ handleDrop(e: React.MouseEvent): void;
21
19
  handleDragEnd(): void;
22
- handleDragOver(e: any): void;
20
+ handleDragOver(e: React.MouseEvent): void;
23
21
  handleDragLeave(): void;
24
- handleDragEnter(e: any): void;
22
+ handleDragEnter(e: React.MouseEvent): void;
25
23
  render(): React.JSX.Element;
26
24
  }
27
25
  export default DragTarget;
@@ -12,7 +12,7 @@ type Props = {
12
12
  };
13
13
  declare class Option extends React.Component<Props> {
14
14
  node: HTMLDivElement;
15
- handleKeyDown(event: any): void;
15
+ handleKeyDown(event: React.KeyboardEvent<HTMLButtonElement>): void;
16
16
  render(): React.ReactNode;
17
17
  }
18
18
  declare class OptionGroup extends React.Component<{
@@ -1,6 +1,5 @@
1
- import { Changeable } from "@khanacademy/perseus";
2
1
  import * as React from "react";
3
- import type { Coords, MarkingsType } from "@khanacademy/perseus-core";
2
+ import type { Coords, MarkingsType, PerseusImageBackground } from "@khanacademy/perseus-core";
4
3
  type Props = {
5
4
  editableSettings: ReadonlyArray<"canvas" | "graph" | "snap" | "image" | "measure">;
6
5
  box: readonly number[];
@@ -10,14 +9,15 @@ type Props = {
10
9
  gridStep: [number, number];
11
10
  snapStep: [number, number];
12
11
  valid: boolean;
13
- backgroundImage: any;
12
+ backgroundImage: PerseusImageBackground;
14
13
  markings: MarkingsType;
15
14
  showProtractor?: boolean;
16
15
  showRuler?: boolean;
17
16
  showTooltips?: boolean;
18
17
  rulerLabel: string;
19
18
  rulerTicks: number;
20
- } & Changeable.ChangeableProps;
19
+ onChange: (values: Record<string, unknown>) => void;
20
+ };
21
21
  type DefaultProps = {
22
22
  editableSettings: Props["editableSettings"];
23
23
  box: Props["box"];
@@ -36,54 +36,45 @@ type DefaultProps = {
36
36
  showTooltips?: Props["showTooltips"];
37
37
  };
38
38
  type State = {
39
- labelsTextbox: string[];
39
+ labelsTextbox: readonly string[];
40
40
  gridStepTextbox: number[];
41
41
  snapStepTextbox: number[];
42
42
  stepTextbox: number[];
43
- rangeTextbox: any[];
44
- backgroundImage: any;
43
+ rangeTextbox: [number, number][];
44
+ backgroundImage: PerseusImageBackground;
45
45
  };
46
46
  declare class GraphSettings extends React.Component<Props, State> {
47
47
  static displayName: "GraphSettings";
48
48
  static defaultProps: DefaultProps;
49
49
  _isMounted: boolean;
50
- constructor(props: any);
51
- getInitialState(): {
52
- labelsTextbox: any;
53
- gridStepTextbox: any;
54
- snapStepTextbox: any;
55
- stepTextbox: any;
56
- rangeTextbox: any;
57
- backgroundImage: any;
58
- };
50
+ constructor(props: Props);
51
+ getInitialState(): State;
59
52
  componentDidMount(): void;
60
- UNSAFE_componentWillReceiveProps(nextProps: any): void;
53
+ UNSAFE_componentWillReceiveProps(nextProps: Props): void;
61
54
  componentWillUnmount(): void;
62
- stateFromProps(props: any): {
63
- labelsTextbox: any;
64
- gridStepTextbox: any;
65
- snapStepTextbox: any;
66
- stepTextbox: any;
67
- rangeTextbox: any;
68
- backgroundImage: any;
69
- };
70
- change(...args: any[]): any;
71
- changeRulerLabel(e: any): void;
72
- changeRulerTicks(e: any): void;
73
- changeBackgroundUrl(e: any): void;
74
- renderLabelChoices(choices: any): React.JSX.Element[];
75
- validRange(range: any): true | "Range must be a valid number" | "Range must have a higher number on the right";
76
- validateStepValue(settings: any): string | true;
77
- validSnapStep(step: any, range: any): string | true;
78
- validGridStep(step: any, range: any): string | true;
79
- validStep(step: any, range: any): string | true;
80
- validBackgroundImageSize(image: any): true | "Image must be smaller than 450px x 450px.";
81
- validateGraphSettings(range: any, step: any, gridStep: any, snapStep: any, image: any): any;
82
- changeLabel(i: any, e: any): void;
83
- changeRange(i: any, values: any): void;
84
- changeStep(step: any): void;
85
- changeSnapStep(snapStep: any): void;
86
- changeGridStep(gridStep: any): void;
55
+ stateFromProps(props: Props): State;
56
+ changeRulerLabel(e: React.ChangeEvent<HTMLSelectElement>): void;
57
+ changeRulerTicks(e: React.ChangeEvent<HTMLSelectElement>): void;
58
+ changeBackgroundUrl(e: React.FocusEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>): void;
59
+ renderLabelChoices(choices: ReadonlyArray<[string, string]>): React.JSX.Element[];
60
+ validRange(range: [number, number]): string | true;
61
+ validateStepValue(settings: {
62
+ step: number;
63
+ range: [number, number];
64
+ name: string;
65
+ minTicks: number;
66
+ maxTicks: number;
67
+ }): string | true;
68
+ validSnapStep(step: number, range: [number, number]): string | true;
69
+ validGridStep(step: number, range: [number, number]): string | true;
70
+ validStep(step: number, range: [number, number]): string | true;
71
+ validBackgroundImageSize(image: PerseusImageBackground): true | "Image must be smaller than 450px x 450px.";
72
+ validateGraphSettings(range: Coords, step: number[], gridStep: number[], snapStep: number[], image: PerseusImageBackground): any;
73
+ changeLabel(i: number, e: React.ChangeEvent<HTMLInputElement>): void;
74
+ changeRange(i: number, values: [number, number]): void;
75
+ changeStep(step: number[]): void;
76
+ changeSnapStep(snapStep: number[]): void;
77
+ changeGridStep(gridStep: number[]): void;
87
78
  changeGraph(): void;
88
79
  render(): React.JSX.Element;
89
80
  }
@@ -13,16 +13,17 @@ type State = {
13
13
  };
14
14
  declare class JsonEditor<TData> extends React.Component<Props<TData>, State> {
15
15
  static displayName: "JsonEditor";
16
- constructor(props: any);
16
+ constructor(props: Props<TData>);
17
17
  getInitialState(): {
18
18
  currentValue: string;
19
19
  valid: boolean;
20
20
  };
21
21
  componentDidUpdate(prevProps: Props<TData>): void;
22
22
  getCurrentValueAsJson(): TData | {} | null;
23
- handleKeyDown(e: any): void;
24
- handleChange(e: any): void;
25
- handleBlur(e: any): void;
23
+ handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>): void;
24
+ handleChange(e: React.ChangeEvent<HTMLTextAreaElement>): void;
25
+ processChange(nextString: string): void;
26
+ handleBlur(e: React.FocusEvent<HTMLTextAreaElement>): void;
26
27
  private typesafeParseOrThrow;
27
28
  render(): React.JSX.Element;
28
29
  }
@@ -9,9 +9,7 @@ type DefaultProps = {
9
9
  type Props = DefaultProps & {
10
10
  children?: React.ReactNode;
11
11
  className?: string;
12
- inlineStyles?: {
13
- [key: string]: any;
14
- };
12
+ inlineStyles?: React.CSSProperties;
15
13
  referrer?: string;
16
14
  target?: string;
17
15
  rel?: string;
package/dist/editor.d.ts CHANGED
@@ -60,7 +60,7 @@ declare class Editor extends React.Component<Props, State> {
60
60
  * those sizes to this.props.images using props.onChange.
61
61
  */
62
62
  _sizeImages: (props: Props) => void;
63
- handleDrop: (e: DragEvent) => void;
63
+ handleDrop: (e: React.MouseEvent) => void;
64
64
  handleChange: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void;
65
65
  _handleKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
66
66
  _maybeCopyWidgets: (e: React.SyntheticEvent<HTMLTextAreaElement>) => void;
package/dist/es/index.js CHANGED
@@ -17,7 +17,7 @@ import { sizing, spacing, semanticColor, font, border } from '@khanacademy/wonde
17
17
  import iconPass from '@phosphor-icons/core/fill/check-circle-fill.svg';
18
18
  import iconWarning from '@phosphor-icons/core/fill/warning-fill.svg';
19
19
  import iconAlert from '@phosphor-icons/core/fill/warning-octagon-fill.svg';
20
- import { BodyText, Heading as Heading$1, BodyMonospace, Footnote, LabelLarge } from '@khanacademy/wonder-blocks-typography';
20
+ import { BodyText, Heading as Heading$1, BodyMonospace } from '@khanacademy/wonder-blocks-typography';
21
21
  import { AccordionSection } from '@khanacademy/wonder-blocks-accordion';
22
22
  import { StyleSheet, css } from 'aphrodite';
23
23
  import Switch from '@khanacademy/wonder-blocks-switch';
@@ -65,7 +65,7 @@ import xIcon from '@phosphor-icons/core/regular/x.svg';
65
65
  import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
66
66
  import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
67
67
 
68
- const libName="@khanacademy/perseus-editor";const libVersion="30.1.0";addLibraryVersionToPerseusDebug(libName,libVersion);
68
+ const libName="@khanacademy/perseus-editor";const libVersion="30.1.1";addLibraryVersionToPerseusDebug(libName,libVersion);
69
69
 
70
70
  var jsxRuntime = {exports: {}};
71
71
 
@@ -1433,11 +1433,11 @@ function ToggleableCaret(props){const iconStyle=props.isExpanded?styles$T.expand
1433
1433
 
1434
1434
  const IssuesPanel=props=>{const{issues=[]}=props;const a11yCheck=props.a11yCheck||{callback:()=>{},isChecked:false};const[showPanel,setShowPanel]=useState(false);const hasWarnings=issues.length>0;const hasErrors=issues.some(issue=>issue.impact==="high");const issuesCount=`${issues.length} issue${issues.length===1?"":"s"}`;const icon=hasErrors?iconAlert:hasWarnings?iconWarning:iconPass;const iconColor=hasErrors?semanticColor.feedback.critical.strong.icon:hasWarnings?semanticColor.feedback.warning.strong.icon:semanticColor.feedback.success.strong.icon;const impactOrder={high:3,medium:2,low:1};const sortedIssues=issues.sort((a,b)=>{if(impactOrder[b.impact]!==impactOrder[a.impact]){return impactOrder[b.impact]-impactOrder[a.impact]}return a.id.localeCompare(b.id)});return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-title",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-title-id",children:jsxRuntimeExports.jsxs(View,{style:{display:"flex",flexDirection:"row",alignItems:"center",gap:"0.25em"},onClick:()=>setShowPanel(!showPanel),children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showPanel}),jsxRuntimeExports.jsx("span",{children:"Issues"})]})}),jsxRuntimeExports.jsx(PhosphorIcon,{icon:icon,size:"medium",color:iconColor,testId:`issues-icon-${icon}`,style:{marginRight:"0.25em"}}),issuesCount]}),showPanel&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-panel",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-content",children:[sortedIssues.map(issue=>jsxRuntimeExports.jsx(IssueDetails,{issue:issue},issue.id)),issues.length===0&&jsxRuntimeExports.jsx("div",{children:"No issues found"}),jsxRuntimeExports.jsx(LabeledSwitch$1,{label:"Include axe-core scan",checked:a11yCheck.isChecked,onChange:()=>{a11yCheck.callback();},style:{marginBlockStart:"1rem"}})]})})]})};
1435
1435
 
1436
- class JsonEditor extends React.Component{getInitialState(){return {currentValue:JSON.stringify(this.props.value,null,4),valid:true}}componentDidUpdate(prevProps){if(!_.isEqual(prevProps.value,this.props.value)){const shouldReplaceContent=!this.state.valid||!_.isEqual(this.props.value,this.getCurrentValueAsJson());if(shouldReplaceContent){this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}}getCurrentValueAsJson(){try{return this.state.currentValue?this.typesafeParseOrThrow(this.state.currentValue):{}}catch{return null}}handleKeyDown(e){if(e.key==="Tab"){const cursorPos=e.target.selectionStart;const v=e.target.value;const textBefore=v.substring(0,cursorPos);const textAfter=v.substring(cursorPos,v.length);e.target.value=textBefore+" "+textAfter;e.target.selectionStart=textBefore.length+4;e.target.selectionEnd=textBefore.length+4;e.preventDefault();this.handleChange(e);}}handleChange(e){const nextString=e.target.value;try{const json=this.typesafeParseOrThrow(nextString);this.setState({currentValue:nextString,valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:nextString,valid:false});}}handleBlur(e){const nextString=e.target.value;try{const json=this.typesafeParseOrThrow(nextString);this.setState({currentValue:JSON.stringify(json,null,4),valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}typesafeParseOrThrow(json){const parsed=this.props.parser(json);if(isSuccess(parsed)){return parsed.value}const parsedFromQuotedString=this.props.parser(JSON.parse(json));if(isSuccess(parsedFromQuotedString)){return parsedFromQuotedString.value}throw new TypeError("JsonEditor: parse failure")}render(){const classes="perseus-json-editor "+(this.state.valid?"valid":"invalid");return jsxRuntimeExports.jsx("textarea",{className:classes,value:this.state.currentValue,onChange:this.handleChange,onKeyDown:this.handleKeyDown,onBlur:this.handleBlur,disabled:this.props.editingDisabled})}constructor(props){super(props);this.state=this.getInitialState();this.handleBlur=this.handleBlur.bind(this);this.handleChange=this.handleChange.bind(this);this.handleKeyDown=this.handleKeyDown.bind(this);}}
1436
+ class JsonEditor extends React.Component{getInitialState(){return {currentValue:JSON.stringify(this.props.value,null,4),valid:true}}componentDidUpdate(prevProps){if(!_.isEqual(prevProps.value,this.props.value)){const shouldReplaceContent=!this.state.valid||!_.isEqual(this.props.value,this.getCurrentValueAsJson());if(shouldReplaceContent){this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}}getCurrentValueAsJson(){try{return this.state.currentValue?this.typesafeParseOrThrow(this.state.currentValue):{}}catch{return null}}handleKeyDown(e){if(e.key==="Tab"){const textarea=e.currentTarget;const cursorPos=textarea.selectionStart;const v=textarea.value;const textBefore=v.substring(0,cursorPos);const textAfter=v.substring(cursorPos,v.length);textarea.value=textBefore+" "+textAfter;textarea.selectionStart=textBefore.length+4;textarea.selectionEnd=textBefore.length+4;e.preventDefault();this.processChange(textarea.value);}}handleChange(e){this.processChange(e.target.value);}processChange(nextString){try{const json=this.typesafeParseOrThrow(nextString);this.setState({currentValue:nextString,valid:true},()=>{this.props.onChange(json);});}catch{this.setState({currentValue:nextString,valid:false});}}handleBlur(e){const nextString=e.target.value;try{const json=this.typesafeParseOrThrow(nextString);this.setState({currentValue:JSON.stringify(json,null,4),valid:true},()=>{this.props.onChange(json);});}catch{this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}typesafeParseOrThrow(json){const parsed=this.props.parser(json);if(isSuccess(parsed)){return parsed.value}const parsedFromQuotedString=this.props.parser(JSON.parse(json));if(isSuccess(parsedFromQuotedString)){return parsedFromQuotedString.value}throw new TypeError("JsonEditor: parse failure")}render(){const classes="perseus-json-editor "+(this.state.valid?"valid":"invalid");return jsxRuntimeExports.jsx("textarea",{className:classes,value:this.state.currentValue,onChange:this.handleChange,onKeyDown:this.handleKeyDown,onBlur:this.handleBlur,disabled:this.props.editingDisabled})}constructor(props){super(props);this.state=this.getInitialState();this.handleBlur=this.handleBlur.bind(this);this.handleChange=this.handleChange.bind(this);this.handleKeyDown=this.handleKeyDown.bind(this);}}
1437
1437
 
1438
1438
  const SectionControlButton=({icon,onClick,title,disabled})=>{return jsxRuntimeExports.jsx(IconButton,{icon:icon,disabled:disabled,"aria-label":title,style:styles$S.button,size:"xsmall",onClick:onClick})};const styles$S=StyleSheet.create({button:{marginLeft:5}});
1439
1439
 
1440
- class DragTarget extends React.Component{handleDrop(e){e.stopPropagation();e.preventDefault();this.setState({dragHover:false});this.props.onDrop(e);}handleDragEnd(){this.setState({dragHover:false});}handleDragOver(e){e.preventDefault();}handleDragLeave(){this.setState({dragHover:false});}handleDragEnter(e){this.setState({dragHover:this.props.shouldDragHighlight(e)});}render(){const opacity=this.state.dragHover?{opacity:.3}:{};const{component:Component,shouldDragHighlight,...forwardProps}=this.props;return jsxRuntimeExports.jsx(Component,{...forwardProps,style:Object.assign({},this.props.style,opacity),onDrop:this.handleDrop,onDragEnd:this.handleDragEnd,onDragOver:this.handleDragOver,onDragEnter:this.handleDragEnter,onDragLeave:this.handleDragLeave})}constructor(props){super(props);this.state={dragHover:false};this.handleDrop=this.handleDrop.bind(this);this.handleDragEnd=this.handleDragEnd.bind(this);this.handleDragOver=this.handleDragOver.bind(this);this.handleDragLeave=this.handleDragLeave.bind(this);this.handleDragEnter=this.handleDragEnter.bind(this);}}DragTarget.defaultProps={component:"div",shouldDragHighlight:()=>true};
1440
+ class DragTarget extends React.Component{handleDrop(e){e.stopPropagation();e.preventDefault();this.setState({dragHover:false});this.props.onDrop(e);}handleDragEnd(){this.setState({dragHover:false});}handleDragOver(e){e.preventDefault();}handleDragLeave(){this.setState({dragHover:false});}handleDragEnter(e){this.setState({dragHover:this.props.shouldDragHighlight(e)});}render(){const opacity=this.state.dragHover?{opacity:.3}:{};const{shouldDragHighlight,...forwardProps}=this.props;return jsxRuntimeExports.jsx(View,{...forwardProps,style:Object.assign({},this.props.style,opacity),onDrop:this.handleDrop,onDragEnd:this.handleDragEnd,onDragOver:this.handleDragOver,onDragEnter:this.handleDragEnter,onDragLeave:this.handleDragLeave})}constructor(props){super(props);this.state={dragHover:false};this.handleDrop=this.handleDrop.bind(this);this.handleDragEnd=this.handleDragEnd.bind(this);this.handleDragOver=this.handleDragOver.bind(this);this.handleDragLeave=this.handleDragLeave.bind(this);this.handleDragEnter=this.handleDragEnter.bind(this);}}DragTarget.defaultProps={shouldDragHighlight:()=>true};
1441
1441
 
1442
1442
  function focusWithChromeStickyFocusBugWorkaround(element){element.focus({preventScroll:true});}const alignmentInfoMap={block:"Block - widget is constrained to the width of the article content container.","wrap-left":"Wrap left - widget is 50% width of the article content container, and is left aligned with text wrapping on the right of the widget.","wrap-right":"Wrap right - widget is 50% width of the article content container, and is right aligned with text wrapping on the left of the widget.","full-width":"Full width - widget extends beyond the width of the article content container."};
1443
1443
 
@@ -1449,7 +1449,7 @@ class WidgetSelect extends React.Component{shouldComponentUpdate(){return false}
1449
1449
 
1450
1450
  function setPerseusClipboardData({text,widgets}){const dummyElement=document.createElement("span");dummyElement.setAttribute("data-perseus-widgets",JSON.stringify(widgets));return navigator.clipboard.write([new ClipboardItem({"text/plain":text,"text/html":dummyElement.outerHTML})])}async function getPerseusClipboardData(){const clipboardItems=await navigator.clipboard.read();let widgets={};let text="";for(const item of clipboardItems){if(item.types.includes("text/html")){const dummyDiv=document.createElement("span");const htmlBlob=await item.getType("text/html");dummyDiv.innerHTML=await htmlBlob.text();const widgetsJson=dummyDiv.querySelector("[data-perseus-widgets]")?.getAttribute("data-perseus-widgets");if(widgetsJson){widgets=JSON.parse(widgetsJson);}}if(item.types.includes("text/plain")){const plainTextBlob=await item.getType("text/plain");text=await plainTextBlob.text();}}return {widgets,text}}
1451
1451
 
1452
- const widgetPlaceholder="[[☃ {id}]]";const widgetRegExp="(\\[\\[☃ {id}\\]\\])";const rWidgetSplit=new RegExp(widgetRegExp.replace("{id}","[a-z-]+ [0-9]+"),"g");const shortcutRegexp=/^\[\[([a-z-]+)$/;const ENDS_WITH_A_PARAGRAPH=/(?:\n{2,}|^\n*)$/;const TRAILING_NEWLINES=/(\n*)$/;const LEADING_NEWLINES=/^(\n*)/;const commafyInteger=n=>{let str=n.toString();if(str.length>=5){str=str.replace(/(\d)(?=(\d{3})+$)/g,"$1{,}");}return str};const makeEndWithAParagraphIfNecessary=content=>{if(!ENDS_WITH_A_PARAGRAPH.test(content)){const match=TRAILING_NEWLINES.exec(content);if(match){const newlines=match[1];return content+"\n\n".slice(0,2-newlines.length)}}return content};const makeStartWithAParagraphAlways=content=>{const match=LEADING_NEWLINES.exec(content);if(!match){return content}const newlines=match[1];return "\n\n".slice(0,2-newlines.length)+content};const IMAGE_REGEX$1=/!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;const allMatches=function(regex,str){const result=[];while(true){const match=regex.exec(str);if(!match){break}result.push(match);}return result};const imageUrlsFromContent=function(content){return allMatches(IMAGE_REGEX$1,content).map(capture=>capture[1])};class Editor extends React.Component{static getDerivedStateFromProps(props,state){return {textAreaValue:props.content,rememberedWidgetsForUndo:{...state.rememberedWidgetsForUndo,...props.widgets}}}componentDidMount(){this.lastUserValue=null;this._sizeImages(this.props);$(this.textarea.current).on("copy cut",this._maybeCopyWidgets).on("paste",this._maybePasteWidgets);}componentDidUpdate(prevProps){const textarea=this.textarea.current;if(this.lastUserValue!=null&&textarea){textarea.focus();textarea.value=this.lastUserValue;textarea.selectionStart=0;textarea.setSelectionRange(0,prevProps.content.length);if(document.execCommand("insertText",false,this.props.content)===false){textarea.value=this.props.content;}this.lastUserValue=null;}if(this.props.content!==prevProps.content){this._sizeImages(this.props);}}getWidgetEditor(id,type){if(!Widgets.getEditor(type)){return}return createElement(WidgetEditor,{...this.props.widgets[id],ref:id,id:id,key:id,onChange:this._handleWidgetEditorChange.bind(this,id),onRemove:this._handleWidgetEditorRemove.bind(this,id),apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}getWidgetsReferencedIn(content){const referencedWidgetIds=getWidgetIdsFromContent(content);const allWidgets={...this.state.rememberedWidgetsForUndo,...this.props.widgets};const referencedWidgets={};for(const id of referencedWidgetIds){if(allWidgets[id]!=null){referencedWidgets[id]=allWidgets[id];}}return referencedWidgets}serialize(){const widgets={};const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));_.each(widgetIds,id=>{widgets[id]=this.refs[id].serialize();});return {content:this.props.content,images:this.props.images,widgets}}render(){let pieces;let widgets;let underlayPieces;let templatesDropDown;let widgetsAndTemplates;let wordCountDisplay;if(this.props.showWordCount){const numChars=PerseusMarkdown.characterCount(this.props.content);const numWords=Math.floor(numChars/6);wordCountDisplay=jsxRuntimeExports.jsx("span",{className:"perseus-editor-word-count",title:"~"+commafyInteger(numWords)+" words ("+commafyInteger(numChars)+" characters)",children:commafyInteger(numWords)});}if(this.props.widgetEnabled){pieces=this.props.content.split(rWidgetSplit);widgets={};underlayPieces=[];for(let i=0;i<pieces.length;i++){if(i%2===0){underlayPieces.push(pieces[i]);}else {const match=Util.rWidgetParts.exec(pieces[i]);if(match!=null){const id=match[1];const type=match[2];const duplicate=id in widgets;widgets[id]=this.getWidgetEditor(id,type);const classes=(duplicate||!widgets[id]?"error ":"")+("");const key=duplicate?i:id;underlayPieces.push(jsxRuntimeExports.jsx("b",{className:classes,children:pieces[i]},key));}}}this.widgetIds=Object.keys(widgets);const insertTemplateString="Insert template…";templatesDropDown=jsxRuntimeExports.jsxs("select",{onChange:this.addTemplate,"data-testid":"editor__template-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:insertTemplateString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"table",children:"Table"}),jsxRuntimeExports.jsx("option",{value:"titledTable",children:"Titled table"}),jsxRuntimeExports.jsx("option",{value:"alignment",children:"Aligned equations"}),jsxRuntimeExports.jsx("option",{value:"piecewise",children:"Piecewise function"}),Object.keys(this.props.additionalTemplates).length>0&&jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),Object.entries(this.props.additionalTemplates).map(([key])=>jsxRuntimeExports.jsx("option",{value:key,children:key},key)),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"allWidgets",children:"All widgets (for testing)"})]});if(!this.props.immutableWidgets){const widgetNodes=Object.values(widgets);widgetsAndTemplates=jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets-selectors",children:[jsxRuntimeExports.jsx(WidgetSelect,{onChange:this._addWidget}),templatesDropDown,wordCountDisplay]}),widgetNodes]});wordCountDisplay=null;}}else {underlayPieces=[this.props.content];}underlayPieces.push(jsxRuntimeExports.jsx("br",{},"end"));const completeTextarea=[jsxRuntimeExports.jsx("div",{className:"perseus-textarea-underlay",ref:this.underlay,children:underlayPieces},"underlay"),jsxRuntimeExports.jsx("textarea",{ref:this.textarea,"aria-label":"Markdown content",onChange:this.handleChange,onKeyDown:this._handleKeyDown,placeholder:this.props.placeholder,disabled:this.props.disabled,value:this.state.textAreaValue},"textarea")];let textareaWrapper;if(this.props.imageUploader){textareaWrapper=jsxRuntimeExports.jsx(DragTarget,{onDrop:this.handleDrop,className:"perseus-textarea-pair",children:completeTextarea});}else {textareaWrapper=jsxRuntimeExports.jsx("div",{className:"perseus-textarea-pair",children:completeTextarea});}const contentWithoutWidgets=this.props.content.replace(/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g,"");const noPrompt=contentWithoutWidgets.trim().length===0;const noWidgets=!/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g.test(this.props.content);const warningStyle={borderTop:"none",padding:4,backgroundColor:"pink"};const editingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{"data-testid":"perseus-single-editor",className:"perseus-single-editor "+(this.props.className||"")+(editingDisabled?" perseus-editor-disabled":""),children:[textareaWrapper,this.props.warnNoPrompt&&noPrompt&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain a prompt"}),this.props.warnNoWidgets&&noWidgets&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain at least one widget"}),wordCountDisplay,widgetsAndTemplates]})}constructor(...args){super(...args),this.underlay=React.createRef(),this.textarea=React.createRef(),this.state={textAreaValue:this.props.content,rememberedWidgetsForUndo:{}},this._handleWidgetEditorChange=(id,newWidgetInfo,cb,silent)=>{const widgets=Object.assign({},this.props.widgets);widgets[id]=Object.assign({},widgets[id],newWidgetInfo);this.props.onChange({widgets},cb,silent);},this._handleWidgetEditorRemove=id=>{if(!confirm("Are you sure you want to delete this item?")){return}const textarea=this.textarea.current;const re=new RegExp(widgetRegExp.replace("{id}",id),"gm");this.props.onChange({content:textarea?.value.replace(re,"")});},this._sizeImages=props=>{const imageUrls=imageUrlsFromContent(props.content);const images=_.pick(props.images,imageUrls);const newImageUrls=_.filter(imageUrls,url=>!images[url]);_.each(newImageUrls,url=>{Util.getImageSize(url,(width,height)=>{images[url]={width:width,height:height};props.onChange({images:_.clone(images)},null,true);});});},this.handleDrop=e=>{const{imageUploader}=this.props;let content=this.state.textAreaValue||"";const dataTransfer=e.dataTransfer;if(!dataTransfer||!imageUploader){return}const files=dataTransfer.files;if(files.length===0){const imageUrl=dataTransfer.getData("URL");if(imageUrl){const newContent=content+"\n\n![]("+imageUrl+")";this.lastUserValue=this.props.content;this.props.onChange({content:newContent});}return}const origContent=this.state.textAreaValue;_(files).chain().map(function(file){if(!file.type.match("image.*")){return null}const sentinel="☃ "+_.uniqueId("image_");content+="\n\n![]("+sentinel+")";return {file:file,sentinel:sentinel}}).reject(_.isNull).tap(()=>{this.lastUserValue=origContent;this.props.onChange({content:content});}).each(fileAndSentinel=>{imageUploader(fileAndSentinel.file,url=>{this.lastUserValue=origContent;this.props.onChange({content:this.state.textAreaValue.replace(fileAndSentinel.sentinel,url)});});});},this.handleChange=e=>{const newValue=e.currentTarget.value;this.setState({textAreaValue:newValue});const widgets=this.getWidgetsReferencedIn(newValue);if(newValue!==this.props.content){this.props.onChange({content:newValue,widgets});}},this._handleKeyDown=e=>{e.stopPropagation();if(e.key==="Tab"){const textarea=this.textarea.current;const word=Util.textarea.getWordBeforeCursor(textarea);const matches=word.string.toLowerCase().match(shortcutRegexp);if(matches!=null){const text=matches[1];const widgets=Widgets.getAllWidgetTypes();const matchingWidgets=widgets.filter(name=>{return name.substring(0,text.length)===text});if(matchingWidgets.length===1){const widgetType=matchingWidgets[0];this._addWidgetToContent(this.props.content,[word.pos.start,word.pos.end+1],widgetType);}e.preventDefault();}}},this._maybeCopyWidgets=e=>{const textarea=e.currentTarget;const selectedText=textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);const widgetIds=_.map(selectedText.match(rWidgetSplit),syntax=>{return Util.rWidgetParts.exec(syntax)[1]});const widgetData=_.pick(this.serialize().widgets,widgetIds);setPerseusClipboardData({text:selectedText,widgets:widgetData}).catch(err=>Log.error("failed to copy data to clipboard","Internal",{cause:err}));},this._maybePasteWidgets=async e=>{e.preventDefault();const{widgets,text:textToBePasted}=await getPerseusClipboardData();const safeWidgetMapping=this._safeWidgetNameMapping(widgets);const safeWidgetData={};for(const[key,data]of Object.entries(widgets)){safeWidgetData[safeWidgetMapping[key]]=data;}const safeText=textToBePasted.replace(rWidgetSplit,syntax=>{const match=Util.rWidgetParts.exec(syntax);const completeWidget=match[0];const widget=match[1];return completeWidget.replace(widget,safeWidgetMapping[widget])});const textarea=e.currentTarget;const selectionStart=textarea.selectionStart;const newContent=this.state.textAreaValue.substr(0,selectionStart)+safeText+this.state.textAreaValue.substr(textarea.selectionEnd);this.lastUserValue=this.state.textAreaValue;this.props.onChange({content:newContent,widgets:{...safeWidgetData,...this.getWidgetsReferencedIn(newContent)}},()=>{const expectedCursorPosition=selectionStart+safeText.length;Util.textarea.moveCursor(textarea,expectedCursorPosition);});},this._safeWidgetNameMapping=widgetData=>{const widgets=_.keys(widgetData).map(name=>name.split(" "));const widgetTypes=_.uniq(widgets.map(widget=>widget[0]));const existingWidgets=_.keys(this.props.widgets).map(name=>name.split(" "));const safeWidgetNums={};_.each(widgetTypes,type=>{safeWidgetNums[type]=_.chain(existingWidgets).filter(existingWidget=>existingWidget[0]===type).map(existingWidget=>+existingWidget[1]+1).max().value();safeWidgetNums[type]=Math.max(safeWidgetNums[type],1);});const safeWidgetMapping={};_.each(widgets,widget=>{const widgetName=widget.join(" ");const widgetType=widget[0];safeWidgetMapping[widgetName]=`${widgetType} ${safeWidgetNums[widgetType]}`;safeWidgetNums[widgetType]++;});return safeWidgetMapping},this._addWidgetToContent=(oldContent,cursorRange,widgetType)=>{const allWidgetIds=_.map(oldContent.match(rWidgetSplit),syntax=>{const match=Util.rWidgetParts.exec(syntax);const type=match[2];const num=+match[3];return [type,num]});const widgetNum=_.reduce(allWidgetIds,(currentNum,otherId)=>{const[otherType,otherNum]=otherId;if(otherType===widgetType){return Math.max(otherNum+1,currentNum)}return currentNum},1);const id=widgetType+" "+widgetNum;const widgetContent=widgetPlaceholder.replace("{id}",id);const isBlock=CoreWidgetRegistry.getDefaultAlignment(widgetType)==="block";const selectedText=oldContent.slice(cursorRange[0],cursorRange[1]);const prelude=oldContent.slice(0,cursorRange[0]);const postlude=oldContent.slice(cursorRange[1]);const newPrelude=isBlock?makeEndWithAParagraphIfNecessary(prelude):prelude;const newPostlude=isBlock?makeStartWithAParagraphAlways(postlude):postlude;const newContent=newPrelude+widgetContent+newPostlude;const newWidgets={...this.props.widgets};const widgetEditor=Widgets.getEditor(widgetType);const initializeWidgetOptionsParams={selectedText};const startWidgetOptions=widgetEditor?.initializeWidgetOptions?.(initializeWidgetOptionsParams);const defaultProps=widgetEditor?.defaultProps;newWidgets[id]={options:startWidgetOptions||defaultProps,type:widgetType,version:Widgets.getVersion(widgetType)};this.lastUserValue=this.props.content;this.props.onChange({content:newContent,widgets:newWidgets},()=>{if(!this.textarea.current){return}Util.textarea.moveCursor(this.textarea.current,newContent.length-postlude.length);});},this._addWidget=widgetType=>{const textarea=this.textarea.current;if(!textarea){return}this._addWidgetToContent(this.props.content,[textarea.selectionStart,textarea.selectionEnd],widgetType);textarea.focus();},this.addTemplate=e=>{const templateType=e.currentTarget.value;if(templateType===""){return}e.currentTarget.value="";let oldContent=this.props.content;oldContent=oldContent.replace(/\n*$/,"\n\n");let template;if(templateType==="table"){template="header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="titledTable"){template="|| **Table title** ||\n"+"header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="alignment"){template="$\\begin{align} \n"+"\\\\\\\\\n"+"\\end{align}$";}else if(templateType==="piecewise"){template="$f(x) = \\begin{cases}\n"+"7 & \\text{if }x=1 \\\\\n"+"f(x-1)+5 & \\text{if }x > 1\n"+"\\end{cases}$";}else if(templateType==="allWidgets"){template=Widgets.getAllWidgetTypes().map(type=>`[[${Util.snowman} ${type} 1]]`).join("\n\n");}else if(templateType in this.props.additionalTemplates){template=this.props.additionalTemplates[templateType];}else {throw new PerseusError("Invalid template type: "+templateType,Errors.InvalidInput,{metadata:{templateType}})}const newContent=oldContent+template;this.lastUserValue=this.props.content;this.props.onChange({content:newContent},this.focusAndMoveToEnd);},this.getSaveWarnings=()=>{const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));const warnings=_(widgetIds).chain().map(id=>{const issuesFunc=this.refs[id].getSaveWarnings;const issues=issuesFunc?issuesFunc():[];return _.map(issues,issue=>id+": "+issue)}).flatten(true).value();return warnings},this.focus=()=>{const textarea=this.textarea.current;if(textarea){textarea.focus();}},this.focusAndMoveToEnd=()=>{this.focus();const textarea=this.textarea.current;if(textarea){textarea.selectionStart=textarea.value.length;textarea.selectionEnd=textarea.value.length;}};}}Editor.defaultProps={content:"",placeholder:"",widgets:{},images:{},disabled:false,widgetEnabled:true,immutableWidgets:false,showWordCount:false,warnNoPrompt:false,warnNoWidgets:false,additionalTemplates:{},apiOptions:ApiOptions.defaults};
1452
+ const widgetPlaceholder="[[☃ {id}]]";const widgetRegExp="(\\[\\[☃ {id}\\]\\])";const rWidgetSplit=new RegExp(widgetRegExp.replace("{id}","[a-z-]+ [0-9]+"),"g");const shortcutRegexp=/^\[\[([a-z-]+)$/;const ENDS_WITH_A_PARAGRAPH=/(?:\n{2,}|^\n*)$/;const TRAILING_NEWLINES=/(\n*)$/;const LEADING_NEWLINES=/^(\n*)/;const commafyInteger=n=>{let str=n.toString();if(str.length>=5){str=str.replace(/(\d)(?=(\d{3})+$)/g,"$1{,}");}return str};const makeEndWithAParagraphIfNecessary=content=>{if(!ENDS_WITH_A_PARAGRAPH.test(content)){const match=TRAILING_NEWLINES.exec(content);if(match){const newlines=match[1];return content+"\n\n".slice(0,2-newlines.length)}}return content};const makeStartWithAParagraphAlways=content=>{const match=LEADING_NEWLINES.exec(content);if(!match){return content}const newlines=match[1];return "\n\n".slice(0,2-newlines.length)+content};const IMAGE_REGEX$1=/!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;const allMatches=function(regex,str){const result=[];while(true){const match=regex.exec(str);if(!match){break}result.push(match);}return result};const imageUrlsFromContent=function(content){return allMatches(IMAGE_REGEX$1,content).map(capture=>capture[1])};class Editor extends React.Component{static getDerivedStateFromProps(props,state){return {textAreaValue:props.content,rememberedWidgetsForUndo:{...state.rememberedWidgetsForUndo,...props.widgets}}}componentDidMount(){this.lastUserValue=null;this._sizeImages(this.props);$(this.textarea.current).on("copy cut",this._maybeCopyWidgets).on("paste",this._maybePasteWidgets);}componentDidUpdate(prevProps){const textarea=this.textarea.current;if(this.lastUserValue!=null&&textarea){textarea.focus();textarea.value=this.lastUserValue;textarea.selectionStart=0;textarea.setSelectionRange(0,prevProps.content.length);if(document.execCommand("insertText",false,this.props.content)===false){textarea.value=this.props.content;}this.lastUserValue=null;}if(this.props.content!==prevProps.content){this._sizeImages(this.props);}}getWidgetEditor(id,type){if(!Widgets.getEditor(type)){return}return createElement(WidgetEditor,{...this.props.widgets[id],ref:id,id:id,key:id,onChange:this._handleWidgetEditorChange.bind(this,id),onRemove:this._handleWidgetEditorRemove.bind(this,id),apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}getWidgetsReferencedIn(content){const referencedWidgetIds=getWidgetIdsFromContent(content);const allWidgets={...this.state.rememberedWidgetsForUndo,...this.props.widgets};const referencedWidgets={};for(const id of referencedWidgetIds){if(allWidgets[id]!=null){referencedWidgets[id]=allWidgets[id];}}return referencedWidgets}serialize(){const widgets={};const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));_.each(widgetIds,id=>{widgets[id]=this.refs[id].serialize();});return {content:this.props.content,images:this.props.images,widgets}}render(){let pieces;let widgets;let underlayPieces;let templatesDropDown;let widgetsAndTemplates;let wordCountDisplay;if(this.props.showWordCount){const numChars=PerseusMarkdown.characterCount(this.props.content);const numWords=Math.floor(numChars/6);wordCountDisplay=jsxRuntimeExports.jsx("span",{className:"perseus-editor-word-count",title:"~"+commafyInteger(numWords)+" words ("+commafyInteger(numChars)+" characters)",children:commafyInteger(numWords)});}if(this.props.widgetEnabled){pieces=this.props.content.split(rWidgetSplit);widgets={};underlayPieces=[];for(let i=0;i<pieces.length;i++){if(i%2===0){underlayPieces.push(pieces[i]);}else {const match=Util.rWidgetParts.exec(pieces[i]);if(match!=null){const id=match[1];const type=match[2];const duplicate=id in widgets;widgets[id]=this.getWidgetEditor(id,type);const classes=(duplicate||!widgets[id]?"error ":"")+("");const key=duplicate?i:id;underlayPieces.push(jsxRuntimeExports.jsx("b",{className:classes,children:pieces[i]},key));}}}this.widgetIds=Object.keys(widgets);const insertTemplateString="Insert template…";templatesDropDown=jsxRuntimeExports.jsxs("select",{onChange:this.addTemplate,"data-testid":"editor__template-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:insertTemplateString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"table",children:"Table"}),jsxRuntimeExports.jsx("option",{value:"titledTable",children:"Titled table"}),jsxRuntimeExports.jsx("option",{value:"alignment",children:"Aligned equations"}),jsxRuntimeExports.jsx("option",{value:"piecewise",children:"Piecewise function"}),Object.keys(this.props.additionalTemplates).length>0&&jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),Object.entries(this.props.additionalTemplates).map(([key])=>jsxRuntimeExports.jsx("option",{value:key,children:key},key)),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"allWidgets",children:"All widgets (for testing)"})]});if(!this.props.immutableWidgets){const widgetNodes=Object.values(widgets);widgetsAndTemplates=jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets-selectors",children:[jsxRuntimeExports.jsx(WidgetSelect,{onChange:this._addWidget}),templatesDropDown,wordCountDisplay]}),widgetNodes]});wordCountDisplay=null;}}else {underlayPieces=[this.props.content];}underlayPieces.push(jsxRuntimeExports.jsx("br",{},"end"));const completeTextarea=[jsxRuntimeExports.jsx("div",{className:"perseus-textarea-underlay",ref:this.underlay,children:underlayPieces},"underlay"),jsxRuntimeExports.jsx("textarea",{ref:this.textarea,"aria-label":"Markdown content",onChange:this.handleChange,onKeyDown:this._handleKeyDown,placeholder:this.props.placeholder,disabled:this.props.disabled,value:this.state.textAreaValue},"textarea")];let textareaWrapper;if(this.props.imageUploader){textareaWrapper=jsxRuntimeExports.jsx(DragTarget,{onDrop:this.handleDrop,className:"perseus-textarea-pair",children:completeTextarea});}else {textareaWrapper=jsxRuntimeExports.jsx("div",{className:"perseus-textarea-pair",children:completeTextarea});}const contentWithoutWidgets=this.props.content.replace(/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g,"");const noPrompt=contentWithoutWidgets.trim().length===0;const noWidgets=!/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g.test(this.props.content);const warningStyle={borderTop:"none",padding:4,backgroundColor:"pink"};const editingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{"data-testid":"perseus-single-editor",className:"perseus-single-editor "+(this.props.className||"")+(editingDisabled?" perseus-editor-disabled":""),children:[textareaWrapper,this.props.warnNoPrompt&&noPrompt&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain a prompt"}),this.props.warnNoWidgets&&noWidgets&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain at least one widget"}),wordCountDisplay,widgetsAndTemplates]})}constructor(...args){super(...args),this.underlay=React.createRef(),this.textarea=React.createRef(),this.state={textAreaValue:this.props.content,rememberedWidgetsForUndo:{}},this._handleWidgetEditorChange=(id,newWidgetInfo,cb,silent)=>{const widgets=Object.assign({},this.props.widgets);widgets[id]=Object.assign({},widgets[id],newWidgetInfo);this.props.onChange({widgets},cb,silent);},this._handleWidgetEditorRemove=id=>{if(!confirm("Are you sure you want to delete this item?")){return}const textarea=this.textarea.current;const re=new RegExp(widgetRegExp.replace("{id}",id),"gm");this.props.onChange({content:textarea?.value.replace(re,"")});},this._sizeImages=props=>{const imageUrls=imageUrlsFromContent(props.content);const images=_.pick(props.images,imageUrls);const newImageUrls=_.filter(imageUrls,url=>!images[url]);_.each(newImageUrls,url=>{Util.getImageSize(url,(width,height)=>{images[url]={width:width,height:height};props.onChange({images:_.clone(images)},null,true);});});},this.handleDrop=e=>{const{imageUploader}=this.props;let content=this.state.textAreaValue||"";const dataTransfer="dataTransfer"in e?e.dataTransfer:null;if(!dataTransfer||!imageUploader){return}const files=dataTransfer.files;if(files.length===0){const imageUrl=dataTransfer.getData("URL");if(imageUrl){const newContent=content+"\n\n![]("+imageUrl+")";this.lastUserValue=this.props.content;this.props.onChange({content:newContent});}return}const origContent=this.state.textAreaValue;_(files).chain().map(function(file){if(!file.type.match("image.*")){return null}const sentinel="☃ "+_.uniqueId("image_");content+="\n\n![]("+sentinel+")";return {file:file,sentinel:sentinel}}).reject(_.isNull).tap(()=>{this.lastUserValue=origContent;this.props.onChange({content:content});}).each(fileAndSentinel=>{imageUploader(fileAndSentinel.file,url=>{this.lastUserValue=origContent;this.props.onChange({content:this.state.textAreaValue.replace(fileAndSentinel.sentinel,url)});});});},this.handleChange=e=>{const newValue=e.currentTarget.value;this.setState({textAreaValue:newValue});const widgets=this.getWidgetsReferencedIn(newValue);if(newValue!==this.props.content){this.props.onChange({content:newValue,widgets});}},this._handleKeyDown=e=>{e.stopPropagation();if(e.key==="Tab"){const textarea=this.textarea.current;const word=Util.textarea.getWordBeforeCursor(textarea);const matches=word.string.toLowerCase().match(shortcutRegexp);if(matches!=null){const text=matches[1];const widgets=Widgets.getAllWidgetTypes();const matchingWidgets=widgets.filter(name=>{return name.substring(0,text.length)===text});if(matchingWidgets.length===1){const widgetType=matchingWidgets[0];this._addWidgetToContent(this.props.content,[word.pos.start,word.pos.end+1],widgetType);}e.preventDefault();}}},this._maybeCopyWidgets=e=>{const textarea=e.currentTarget;const selectedText=textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);const widgetIds=_.map(selectedText.match(rWidgetSplit),syntax=>{return Util.rWidgetParts.exec(syntax)[1]});const widgetData=_.pick(this.serialize().widgets,widgetIds);setPerseusClipboardData({text:selectedText,widgets:widgetData}).catch(err=>Log.error("failed to copy data to clipboard","Internal",{cause:err}));},this._maybePasteWidgets=async e=>{e.preventDefault();const{widgets,text:textToBePasted}=await getPerseusClipboardData();const safeWidgetMapping=this._safeWidgetNameMapping(widgets);const safeWidgetData={};for(const[key,data]of Object.entries(widgets)){safeWidgetData[safeWidgetMapping[key]]=data;}const safeText=textToBePasted.replace(rWidgetSplit,syntax=>{const match=Util.rWidgetParts.exec(syntax);const completeWidget=match[0];const widget=match[1];return completeWidget.replace(widget,safeWidgetMapping[widget])});const textarea=e.currentTarget;const selectionStart=textarea.selectionStart;const newContent=this.state.textAreaValue.substr(0,selectionStart)+safeText+this.state.textAreaValue.substr(textarea.selectionEnd);this.lastUserValue=this.state.textAreaValue;this.props.onChange({content:newContent,widgets:{...safeWidgetData,...this.getWidgetsReferencedIn(newContent)}},()=>{const expectedCursorPosition=selectionStart+safeText.length;Util.textarea.moveCursor(textarea,expectedCursorPosition);});},this._safeWidgetNameMapping=widgetData=>{const widgets=_.keys(widgetData).map(name=>name.split(" "));const widgetTypes=_.uniq(widgets.map(widget=>widget[0]));const existingWidgets=_.keys(this.props.widgets).map(name=>name.split(" "));const safeWidgetNums={};_.each(widgetTypes,type=>{safeWidgetNums[type]=_.chain(existingWidgets).filter(existingWidget=>existingWidget[0]===type).map(existingWidget=>+existingWidget[1]+1).max().value();safeWidgetNums[type]=Math.max(safeWidgetNums[type],1);});const safeWidgetMapping={};_.each(widgets,widget=>{const widgetName=widget.join(" ");const widgetType=widget[0];safeWidgetMapping[widgetName]=`${widgetType} ${safeWidgetNums[widgetType]}`;safeWidgetNums[widgetType]++;});return safeWidgetMapping},this._addWidgetToContent=(oldContent,cursorRange,widgetType)=>{const allWidgetIds=_.map(oldContent.match(rWidgetSplit),syntax=>{const match=Util.rWidgetParts.exec(syntax);const type=match[2];const num=+match[3];return [type,num]});const widgetNum=_.reduce(allWidgetIds,(currentNum,otherId)=>{const[otherType,otherNum]=otherId;if(otherType===widgetType){return Math.max(otherNum+1,currentNum)}return currentNum},1);const id=widgetType+" "+widgetNum;const widgetContent=widgetPlaceholder.replace("{id}",id);const isBlock=CoreWidgetRegistry.getDefaultAlignment(widgetType)==="block";const selectedText=oldContent.slice(cursorRange[0],cursorRange[1]);const prelude=oldContent.slice(0,cursorRange[0]);const postlude=oldContent.slice(cursorRange[1]);const newPrelude=isBlock?makeEndWithAParagraphIfNecessary(prelude):prelude;const newPostlude=isBlock?makeStartWithAParagraphAlways(postlude):postlude;const newContent=newPrelude+widgetContent+newPostlude;const newWidgets={...this.props.widgets};const widgetEditor=Widgets.getEditor(widgetType);const initializeWidgetOptionsParams={selectedText};const startWidgetOptions=widgetEditor?.initializeWidgetOptions?.(initializeWidgetOptionsParams);const defaultProps=widgetEditor?.defaultProps;newWidgets[id]={options:startWidgetOptions||defaultProps,type:widgetType,version:Widgets.getVersion(widgetType)};this.lastUserValue=this.props.content;this.props.onChange({content:newContent,widgets:newWidgets},()=>{if(!this.textarea.current){return}Util.textarea.moveCursor(this.textarea.current,newContent.length-postlude.length);});},this._addWidget=widgetType=>{const textarea=this.textarea.current;if(!textarea){return}this._addWidgetToContent(this.props.content,[textarea.selectionStart,textarea.selectionEnd],widgetType);textarea.focus();},this.addTemplate=e=>{const templateType=e.currentTarget.value;if(templateType===""){return}e.currentTarget.value="";let oldContent=this.props.content;oldContent=oldContent.replace(/\n*$/,"\n\n");let template;if(templateType==="table"){template="header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="titledTable"){template="|| **Table title** ||\n"+"header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="alignment"){template="$\\begin{align} \n"+"\\\\\\\\\n"+"\\end{align}$";}else if(templateType==="piecewise"){template="$f(x) = \\begin{cases}\n"+"7 & \\text{if }x=1 \\\\\n"+"f(x-1)+5 & \\text{if }x > 1\n"+"\\end{cases}$";}else if(templateType==="allWidgets"){template=Widgets.getAllWidgetTypes().map(type=>`[[${Util.snowman} ${type} 1]]`).join("\n\n");}else if(templateType in this.props.additionalTemplates){template=this.props.additionalTemplates[templateType];}else {throw new PerseusError("Invalid template type: "+templateType,Errors.InvalidInput,{metadata:{templateType}})}const newContent=oldContent+template;this.lastUserValue=this.props.content;this.props.onChange({content:newContent},this.focusAndMoveToEnd);},this.getSaveWarnings=()=>{const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));const warnings=_(widgetIds).chain().map(id=>{const issuesFunc=this.refs[id].getSaveWarnings;const issues=issuesFunc?issuesFunc():[];return _.map(issues,issue=>id+": "+issue)}).flatten(true).value();return warnings},this.focus=()=>{const textarea=this.textarea.current;if(textarea){textarea.focus();}},this.focusAndMoveToEnd=()=>{this.focus();const textarea=this.textarea.current;if(textarea){textarea.selectionStart=textarea.value.length;textarea.selectionEnd=textarea.value.length;}};}}Editor.defaultProps={content:"",placeholder:"",widgets:{},images:{},disabled:false,widgetEnabled:true,immutableWidgets:false,showWordCount:false,warnNoPrompt:false,warnNoWidgets:false,additionalTemplates:{},apiOptions:ApiOptions.defaults};
1453
1453
 
1454
1454
  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();}}
1455
1455
 
@@ -1530,9 +1530,9 @@ const{InlineIcon: InlineIcon$1,TextInput: TextInput$4}=components;class GradedGr
1530
1530
 
1531
1531
  class GradedGroupSetEditor extends React.Component{UNSAFE_componentWillMount(){this._editors=[];}render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[this.renderGroups(),jsxRuntimeExports.jsx("button",{onClick:this.addGroup,children:"Add group"})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.getSaveWarnings=()=>{return [].concat(...this._editors.map(editor=>editor?editor.getSaveWarnings():[]))},this.serialize=()=>{return {gradedGroups:this.props.gradedGroups}},this.renderGroups=()=>{if(!this.props.gradedGroups){return null}return this.props.gradedGroups.map((group,i)=>jsxRuntimeExports.jsx(GradedGroupEditor,{ref:el=>this._editors[i]=el,...group,apiOptions:this.props.apiOptions,widgetEnabled:true,immutableWidgets:false,onChange:data=>this.change("gradedGroups",setArrayItem(this.props.gradedGroups,i,{...this.props.gradedGroups[i],...data}))},i))},this.addGroup=()=>{const groups=this.props.gradedGroups||[];this.change("gradedGroups",groups.concat([GradedGroupEditor.defaultProps]));};}}GradedGroupSetEditor.propTypes={...Changeable.propTypes,apiOptions:ApiOptions.propTypes,gradedGroups:PropTypes.array,onChange:PropTypes.func.isRequired};GradedGroupSetEditor.widgetName="graded-group-set";GradedGroupSetEditor.defaultProps=gradedGroupSetLogic.defaultWidgetOptions;const setArrayItem=(list,i,value)=>[...list.slice(0,i),value,...list.slice(i+1)];
1532
1532
 
1533
- const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$i,RangeInput: RangeInput$5}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}change(...args){return Changeable.change.apply(this,args)}changeRulerLabel(e){this.change({rulerLabel:e.target.value});}changeRulerTicks(e){this.change({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"canvas-size",value:this.props.box,onChange:box=>{this.change({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.change({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.change=this.change.bind(this);this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1533
+ const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$i,RangeInput: RangeInput$5}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}changeRulerLabel(e){this.props.onChange({rulerLabel:e.target.value});}changeRulerTicks(e){this.props.onChange({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&"key"in e&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=(image.width??0)<=450&&(image.height??0)<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=this.state.rangeTextbox.map(range=>range.map(Number));const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.props.onChange({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.props.onChange({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"canvas-size",value:this.props.box,onChange:box=>{this.props.onChange({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:value=>this.props.onChange({markings:value})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.props.onChange({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.props.onChange({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1534
1534
 
1535
- const{InfoTip: InfoTip$h,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,correct:this.props.correct,handleUserInput:(userInput,cb)=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct},cb);},availableTypes:this.props.availableTypes,trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:this.change("graph")}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.propTypes={...Changeable.propTypes};GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1535
+ const{InfoTip: InfoTip$h,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,correct:this.props.correct,handleUserInput:userInput=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct});},availableTypes:[...this.props.availableTypes],trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid===true,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:newProps=>this.props.onChange({graph:{...this.props.graph,...newProps}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1536
1536
 
1537
1537
  class GroupEditor extends React.Component{serialize(){invariant(this.editor.current,"cannot serialize GroupEditor without Editor");return {...this.editor.current.serialize()}}render(){return jsxRuntimeExports.jsx("div",{className:"perseus-group-editor",children:jsxRuntimeExports.jsx(Editor,{ref:this.editor,content:this.props.content,widgets:this.props.widgets,apiOptions:this.props.apiOptions,images:this.props.images,widgetEnabled:true,immutableWidgets:false,onChange:this.props.onChange})})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()};}}GroupEditor.propTypes={content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GroupEditor.widgetName="group";GroupEditor.defaultProps=groupLogic.defaultWidgetOptions;
1538
1538
 
@@ -1554,7 +1554,7 @@ function ImageDimensionsInput({backgroundImage,onChange}){function handleWidthCh
1554
1554
 
1555
1555
  function ImageScaleInput({backgroundImage,scale,onChange}){const width=backgroundImage.width??0;const height=backgroundImage.height??0;function handleScaleChange(newScale){const scaleNum=Number(newScale);if(isNaN(scaleNum)||scaleNum<=0){return}onChange({scale:scaleNum});}function handleScaledWidthChange(newScaledWidth){const newScaledWidthNum=Number(newScaledWidth);if(isNaN(newScaledWidthNum)||newScaledWidthNum<=0){return}const newScale=newScaledWidthNum/width;onChange({scale:newScale});}function handleScaledHeightChange(newScaledHeight){const newScaledHeightNum=Number(newScaledHeight);if(isNaN(newScaledHeightNum)||newScaledHeightNum<=0){return}const newScale=newScaledHeightNum/height;onChange({scale:newScale});}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}});}return jsxRuntimeExports.jsxs("div",{className:styles$M.dimensionsContainer,children:[jsxRuntimeExports.jsxs(BodyMonospace,{children:["Dimensions: ",width," x ",height]}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",size:"small",startIcon:arrowCounterClockwise,onClick:handleResetToOriginalSize,children:"Recalculate original size"}),jsxRuntimeExports.jsx("div",{className:styles$M.horizontalLine}),jsxRuntimeExports.jsx(LabeledField,{label:"Scale",description:"Use 1 to display image at original size.",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:scale.toString(),min:0,onChange:handleScaleChange}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$M.dimensionsFieldContainer,children:[jsxRuntimeExports.jsx(LabeledField,{label:"Scaled Width",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:(width*scale).toString(),min:0,onChange:handleScaledWidthChange}),styles:wbFieldStyles}),jsxRuntimeExports.jsx("span",{className:styles$M.xSpan,children:"x"}),jsxRuntimeExports.jsx(LabeledField,{label:"Scaled Height",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:(height*scale).toString(),min:0,onChange:handleScaledHeightChange}),styles:wbFieldStyles})]})]})}
1556
1556
 
1557
- 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,backgroundImage,scale=1,apiOptions,caption,decorative,longDescription,title,onChange}){const[altFieldWarning,setAltFieldWarning]=React.useState(null);const scaleFF=isFeatureOn({apiOptions},"image-widget-upgrade-scale");if(!backgroundImage.url){return null}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.jsx(ImagePreview,{src:backgroundImage.url,alt:`Preview: ${alt||"No alt text"}`,width:backgroundImage.width,height:backgroundImage.height}),styles:wbFieldStyles}),scaleFF?jsxRuntimeExports.jsx(ImageScaleInput,{backgroundImage:backgroundImage,scale:scale,onChange:onChange}):jsxRuntimeExports.jsx(ImageDimensionsInput,{backgroundImage:backgroundImage,onChange:onChange}),jsxRuntimeExports.jsx(DecorativeToggle,{decorative:decorative,hasPopulatedFields:hasPopulatedFields,onChange:onChange}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(TextArea,{value:title??"",onChange:value=>onChange({title:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$M.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,autoResize:true}),styles:wbFieldStylesWithDescription}),jsxRuntimeExports.jsxs(Footnote,{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,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(TextArea,{value:caption??"",onChange:value=>onChange({caption:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles})]})}const wbStyles=StyleSheet.create({characterCounter:{position:"absolute",bottom:0,right:8}});
1557
+ 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,backgroundImage,scale=1,apiOptions,caption,decorative,longDescription,title,onChange}){const[altFieldWarning,setAltFieldWarning]=React.useState(null);const scaleFF=isFeatureOn({apiOptions},"image-widget-upgrade-scale");if(!backgroundImage.url){return null}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.jsx(ImagePreview,{src:backgroundImage.url,alt:`Preview: ${alt||"No alt text"}`,width:backgroundImage.width,height:backgroundImage.height}),styles:wbFieldStyles}),scaleFF?jsxRuntimeExports.jsx(ImageScaleInput,{backgroundImage:backgroundImage,scale:scale,onChange:onChange}):jsxRuntimeExports.jsx(ImageDimensionsInput,{backgroundImage:backgroundImage,onChange:onChange}),jsxRuntimeExports.jsx(DecorativeToggle,{decorative:decorative,hasPopulatedFields:hasPopulatedFields,onChange:onChange}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(TextArea,{value:title??"",onChange:value=>onChange({title:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$M.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,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,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(TextArea,{value:caption??"",onChange:value=>onChange({caption:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles})]})}const wbStyles=StyleSheet.create({characterCounter:{position:"absolute",bottom:0,right:8}});
1558
1558
 
1559
1559
  const INTERNALLY_HOSTED_DOMAINS="("+"ka-.*.s3.amazonaws.com|"+"(fastly|cdn).kastatic.org|"+"khanacademy.org|"+"kasandbox.org"+")";const INTERNALLY_HOSTED_URL_RE=new RegExp("^(https?|web\\+graphie)://[^/]*"+INTERNALLY_HOSTED_DOMAINS);function ImageUrlInput({backgroundImage,onChange}){const uniqueId=React__default.useId();const urlId=`${uniqueId}-url`;const[urlFieldValue,setUrlFieldValue]=React__default.useState(backgroundImage.url||"");const[backgroundImageError,setBackgroundImageError]=React__default.useState(null);React__default.useEffect(()=>{setUrlFieldValue(backgroundImage.url||"");},[backgroundImage.url]);function setUrl(url,width,height){const image={...backgroundImage};image.url=url;image.width=width;image.height=height;const box=[image.width,image.height];onChange({backgroundImage:image,box:box});}async function onUrlChange(url){setBackgroundImageError(null);if(!url){setUrl(url,0,0);return}if(url===backgroundImage.url){return}if(url&&!INTERNALLY_HOSTED_URL_RE.test(url)){setBackgroundImageError("Images must be from sites hosted by Khan Academy. "+"Please input a Khan Academy-owned address, or use the "+"Add Image tool to rehost an existing image");return}try{const size=await Util.getImageSizeModern(url);setUrl(url,size[0],size[1]);}catch(error){setBackgroundImageError(`There was an error loading the image URL: ${JSON.stringify(error,null,2)}`);}}return jsxRuntimeExports.jsx(LabeledField,{label:"Image URL",description:"Paste an image or graphie image URL.",field:jsxRuntimeExports.jsx(TextField,{id:urlId,value:urlFieldValue,onBlur:e=>onUrlChange(e.target.value),onChange:value=>setUrlFieldValue(value)}),errorMessage:backgroundImageError,styles:wbFieldStylesWithDescription})}
1560
1560
 
@@ -1590,7 +1590,7 @@ const{getDependencies: getDependencies$2}=Dependencies;class PointEditor extends
1590
1590
 
1591
1591
  const{getDependencies: getDependencies$1}=Dependencies;class RectangleEditor extends React.Component{render(){const{TeX}=getDependencies$1();return jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Bottom left: ",jsxRuntimeExports.jsx(TeX,{children:"\\Large("}),jsxRuntimeExports.jsx(MathquillInput,{value:this.props.coordX,onChange:this.change("coordX")}),jsxRuntimeExports.jsx(TeX,{children:","})," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.coordY,onChange:this.change("coordY")}),jsxRuntimeExports.jsx(TeX,{children:"\\Large)"})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Width:"," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.width,onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Height:"," ",jsxRuntimeExports.jsx(MathquillInput,{value:this.props.height,onChange:this.change("height")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(ColorPicker,{value:this.props.color,lightColors:true,onChange:this.change("color")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:"You want a border? Sorry, draw your own."})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}RectangleEditor.defaultProps={coordX:"-5",coordY:"5",width:"2",height:"3",color:KhanColors.LIGHT_BLUE};
1592
1592
 
1593
- const{getDependencies}=Dependencies;const{unescapeMathMode}=Util;class InteractionEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({usedVarSubscripts:this._getAllVarSubscripts(nextProps.elements),usedFunctionNames:this._getAllFunctionNames(nextProps.elements)});}_getAllVarSubscripts(elements){return _.map(_.where(elements,{type:"movable-point"}),element=>element.options.varSubscript).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.startSubscript)).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.endSubscript))}_getAllFunctionNames(elements){return _.map(_.where(elements,{type:"function"}),element=>element.options.funcName)}render(){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-interaction-editor",children:[jsxRuntimeExports.jsxs(ElementContainer,{title:"Grid settings",children:[jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["canvas","graph"],box:this.props.graph.box,labels:this.props.graph.labels,range:this.props.graph.range,step:this.props.graph.tickStep,gridStep:this.props.graph.gridStep,markings:this.props.graph.markings,onChange:this._updateGraphProps}),jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:this.props.graph.valid!==true&&jsxRuntimeExports.jsx("div",{children:this.props.graph.valid})})]}),_.map(this.props.elements,function(element,n){if(element.type==="movable-point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable point"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.varSubscript+"}, y_{"+element.options.varSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovablePointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="movable-line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable line"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.startSubscript+"}, y_{"+element.options.startSubscript+"})"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.endSubscript+"}, y_{"+element.options.endSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovableLineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Point"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(PointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Line"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.startX+", "+element.options.startY+")"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.endX+", "+element.options.endY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(LineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="function"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Function"," ",jsxRuntimeExports.jsx(TeX,{children:element.options.funcName+"(x) = "+element.options.value})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(FunctionEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="parametric"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsx("span",{children:"Parametric"}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(ParametricEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="label"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Label"," ",jsxRuntimeExports.jsx(TeX,{children:unescapeMathMode(element.options.label)})," "]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(LabelEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}if(element.type==="rectangle"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Rectangle"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})," — ",jsxRuntimeExports.jsx(TeX,{children:element.options.width+" \\times "+element.options.height})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(RectangleEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.change({elements:elements});}})},element.key)}},this),jsxRuntimeExports.jsx("div",{className:"perseus-widget-interaction-editor-select-element",children:jsxRuntimeExports.jsxs("select",{onChange:this._addNewElement,children:[jsxRuntimeExports.jsxs("option",{value:"",children:["Add an element","…"]}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"point",children:"Point"}),jsxRuntimeExports.jsx("option",{value:"line",children:"Line segment"}),jsxRuntimeExports.jsx("option",{value:"function",children:"Function plot"}),jsxRuntimeExports.jsx("option",{value:"parametric",children:"Parametric plot"}),jsxRuntimeExports.jsx("option",{value:"label",children:"Label"}),jsxRuntimeExports.jsx("option",{value:"rectangle",children:"Rectangle"}),jsxRuntimeExports.jsx("option",{value:"movable-point",children:"★ Movable point"}),jsxRuntimeExports.jsx("option",{value:"movable-line",children:"★ Movable line segment"})]})})]})}constructor(...args){super(...args),this.state={usedVarSubscripts:this._getAllVarSubscripts(this.props.elements),usedFunctionNames:this._getAllFunctionNames(this.props.elements)},this._updateGraphProps=newProps=>{this.change({graph:_.extend(_.omit(newProps,"step"),{tickStep:newProps.step})});},this._addNewElement=e=>{const elementType=e.target.value;if(elementType===""){return}e.target.value="";const newElement={type:elementType,key:elementType+"-"+(Math.random()*0xffffff<<0).toString(16),options:elementType==="point"?_.clone(PointEditor.defaultProps):elementType==="line"?_.clone(LineEditor.defaultProps):elementType==="movable-point"?_.clone(MovablePointEditor.defaultProps):elementType==="movable-line"?_.clone(MovableLineEditor.defaultProps):elementType==="function"?_.clone(FunctionEditor.defaultProps):elementType==="parametric"?_.clone(ParametricEditor.defaultProps):elementType==="label"?_.clone(LabelEditor.defaultProps):elementType==="rectangle"?_.clone(RectangleEditor.defaultProps):{}};let nextSubscript;if(elementType==="movable-point"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.varSubscript=nextSubscript;}else if(elementType==="movable-line"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.startSubscript=nextSubscript;newElement.options.endSubscript=nextSubscript+1;}else if(elementType==="function"){const nextLetter=String.fromCharCode(_.max([_.max(_.map(this.state.usedFunctionNames,function(c){return c.charCodeAt(0)})),"e".charCodeAt(0)])+1);newElement.options.funcName=nextLetter;}this.change({elements:this.props.elements.concat(newElement)});},this._deleteElement=index=>{const element=this.props.elements[index];this.change({elements:_.without(this.props.elements,element)});},this._moveElementUp=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index-1,0,element);this.change({elements:newElements});},this._moveElementDown=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index+1,0,element);this.change({elements:newElements});},this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}InteractionEditor.widgetName="interaction";InteractionEditor.defaultProps=interactionLogic.defaultWidgetOptions;
1593
+ const{getDependencies}=Dependencies;const{unescapeMathMode}=Util;class InteractionEditor extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({usedVarSubscripts:this._getAllVarSubscripts(nextProps.elements),usedFunctionNames:this._getAllFunctionNames(nextProps.elements)});}_getAllVarSubscripts(elements){return _.map(_.where(elements,{type:"movable-point"}),element=>element.options.varSubscript).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.startSubscript)).concat(_.map(_.where(elements,{type:"movable-line"}),element=>element.options.endSubscript))}_getAllFunctionNames(elements){return _.map(_.where(elements,{type:"function"}),element=>element.options.funcName)}render(){const{TeX}=getDependencies();return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-interaction-editor",children:[jsxRuntimeExports.jsxs(ElementContainer,{title:"Grid settings",children:[jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["canvas","graph"],box:this.props.graph.box,labels:this.props.graph.labels,range:this.props.graph.range,step:this.props.graph.tickStep,gridStep:this.props.graph.gridStep,markings:this.props.graph.markings,onChange:this._updateGraphProps}),jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:this.props.graph.valid!==true&&jsxRuntimeExports.jsx("div",{children:this.props.graph.valid})})]}),_.map(this.props.elements,function(element,n){if(element.type==="movable-point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable point"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.varSubscript+"}, y_{"+element.options.varSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovablePointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="movable-line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Movable line"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.startSubscript+"}, y_{"+element.options.startSubscript+"})"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"(x_{"+element.options.endSubscript+"}, y_{"+element.options.endSubscript+"})"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(MovableLineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="point"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Point"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(PointEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="line"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Line"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.startX+", "+element.options.startY+")"})," ","to"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.endX+", "+element.options.endY+")"})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement.bind(this,n),children:jsxRuntimeExports.jsx(LineEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="function"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Function"," ",jsxRuntimeExports.jsx(TeX,{children:element.options.funcName+"(x) = "+element.options.value})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(FunctionEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="parametric"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsx("span",{children:"Parametric"}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(ParametricEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="label"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Label"," ",jsxRuntimeExports.jsx(TeX,{children:unescapeMathMode(element.options.label)})," "]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(LabelEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}if(element.type==="rectangle"){return jsxRuntimeExports.jsx(ElementContainer,{title:jsxRuntimeExports.jsxs("span",{children:["Rectangle"," ",jsxRuntimeExports.jsx(TeX,{children:"("+element.options.coordX+", "+element.options.coordY+")"})," — ",jsxRuntimeExports.jsx(TeX,{children:element.options.width+" \\times "+element.options.height})]}),onUp:n===0?null:this._moveElementUp.bind(this,n),onDown:n===this.props.elements.length-1?null:this._moveElementDown.bind(this,n),onDelete:this._deleteElement,children:jsxRuntimeExports.jsx(RectangleEditor,{...element.options,onChange:newProps=>{const elements=JSON.parse(JSON.stringify(this.props.elements));_.extend(elements[n].options,newProps);this.props.onChange({elements:elements});}})},element.key)}},this),jsxRuntimeExports.jsx("div",{className:"perseus-widget-interaction-editor-select-element",children:jsxRuntimeExports.jsxs("select",{onChange:this._addNewElement,children:[jsxRuntimeExports.jsxs("option",{value:"",children:["Add an element","…"]}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"point",children:"Point"}),jsxRuntimeExports.jsx("option",{value:"line",children:"Line segment"}),jsxRuntimeExports.jsx("option",{value:"function",children:"Function plot"}),jsxRuntimeExports.jsx("option",{value:"parametric",children:"Parametric plot"}),jsxRuntimeExports.jsx("option",{value:"label",children:"Label"}),jsxRuntimeExports.jsx("option",{value:"rectangle",children:"Rectangle"}),jsxRuntimeExports.jsx("option",{value:"movable-point",children:"★ Movable point"}),jsxRuntimeExports.jsx("option",{value:"movable-line",children:"★ Movable line segment"})]})})]})}constructor(...args){super(...args),this.state={usedVarSubscripts:this._getAllVarSubscripts(this.props.elements),usedFunctionNames:this._getAllFunctionNames(this.props.elements)},this._updateGraphProps=newProps=>{this.props.onChange({graph:{...this.props.graph,..._.omit(newProps,"step"),tickStep:newProps.step}});},this._addNewElement=e=>{const elementType=e.target.value;if(elementType===""){return}e.target.value="";const newElement={type:elementType,key:elementType+"-"+(Math.random()*0xffffff<<0).toString(16),options:elementType==="point"?_.clone(PointEditor.defaultProps):elementType==="line"?_.clone(LineEditor.defaultProps):elementType==="movable-point"?_.clone(MovablePointEditor.defaultProps):elementType==="movable-line"?_.clone(MovableLineEditor.defaultProps):elementType==="function"?_.clone(FunctionEditor.defaultProps):elementType==="parametric"?_.clone(ParametricEditor.defaultProps):elementType==="label"?_.clone(LabelEditor.defaultProps):elementType==="rectangle"?_.clone(RectangleEditor.defaultProps):{}};let nextSubscript;if(elementType==="movable-point"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.varSubscript=nextSubscript;}else if(elementType==="movable-line"){nextSubscript=_.max([_.max(this.state.usedVarSubscripts),-1])+1;newElement.options.startSubscript=nextSubscript;newElement.options.endSubscript=nextSubscript+1;}else if(elementType==="function"){const nextLetter=String.fromCharCode(_.max([_.max(_.map(this.state.usedFunctionNames,function(c){return c.charCodeAt(0)})),"e".charCodeAt(0)])+1);newElement.options.funcName=nextLetter;}this.props.onChange({elements:this.props.elements.concat(newElement)});},this._deleteElement=index=>{const element=this.props.elements[index];this.props.onChange({elements:_.without(this.props.elements,element)});},this._moveElementUp=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index-1,0,element);this.props.onChange({elements:newElements});},this._moveElementDown=index=>{const element=this.props.elements[index];const newElements=_.without(this.props.elements,element);newElements.splice(index+1,0,element);this.props.onChange({elements:newElements});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}InteractionEditor.widgetName="interaction";InteractionEditor.defaultProps=interactionLogic.defaultWidgetOptions;
1594
1594
 
1595
1595
  var styles$J = {"singleSelectShort":"perseus_wAZzFxEx","row":"perseus_6FquBkGo"};
1596
1596
 
@@ -1675,7 +1675,7 @@ const StartCoordsCircle=props=>{const{startCoords,onChange}=props;const[radiusSt
1675
1675
 
1676
1676
  var styles$h = {"tile":"perseus_MaeHUJMQ","row":"perseus_tg5HzCB6","textFieldWrapper":"perseus_c6LzNJd7"};
1677
1677
 
1678
- const StartCoordsExponential=props=>{const{startCoords,onChange}=props;const{coords,asymptote}=startCoords;const[asymptoteYState,setAsymptoteYState]=React.useState(asymptote.toString());React.useEffect(()=>{setAsymptoteYState(asymptote.toString());},[asymptote]);function handleAsymptoteYChange(newValue){setAsymptoteYState(newValue);if(isNaN(+newValue)||newValue===""){return}const newY=parseFloat(newValue);onChange({coords:[coords[0],coords[1]],asymptote:newY});}return jsxRuntimeExports.jsxs(View,{className:styles$h.tile,children:[jsxRuntimeExports.jsxs(View,{className:styles$h.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coords[0],labels:["x","y"],onChange:value=>onChange({coords:[value,coords[1]],asymptote})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(View,{className:styles$h.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coords[1],labels:["x","y"],onChange:value=>onChange({coords:[coords[0],value],asymptote})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",className:styles$h.row,children:["Asymptote y =",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{className:styles$h.textFieldWrapper,children:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:asymptoteYState,onChange:handleAsymptoteYChange})})]})]})};
1678
+ const StartCoordsExponential=props=>{const{startCoords,onChange}=props;const{coords,asymptote}=startCoords;const[asymptoteYState,setAsymptoteYState]=React.useState(asymptote.toString());React.useEffect(()=>{setAsymptoteYState(asymptote.toString());},[asymptote]);function handleAsymptoteYChange(newValue){setAsymptoteYState(newValue);if(isNaN(+newValue)||newValue===""){return}const newY=parseFloat(newValue);onChange({coords:[coords[0],coords[1]],asymptote:newY});}return jsxRuntimeExports.jsxs(View,{className:styles$h.tile,children:[jsxRuntimeExports.jsxs(View,{className:styles$h.row,children:[jsxRuntimeExports.jsx(BodyText,{weight:"bold",children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coords[0],labels:["x","y"],onChange:value=>onChange({coords:[value,coords[1]],asymptote})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(View,{className:styles$h.row,children:[jsxRuntimeExports.jsx(BodyText,{weight:"bold",children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coords[1],labels:["x","y"],onChange:value=>onChange({coords:[coords[0],value],asymptote})})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsxs(BodyText,{weight:"bold",tag:"label",className:styles$h.row,children:["Asymptote y =",jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{className:styles$h.textFieldWrapper,children:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:asymptoteYState,onChange:handleAsymptoteYChange})})]})]})};
1679
1679
 
1680
1680
  const StartCoordsLine=props=>{const{startCoords,onChange}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:styles$g.tile,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Point 1:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[0],labels:["x","y"],onChange:value=>onChange([value,startCoords[1]])})]}),jsxRuntimeExports.jsxs(View,{style:styles$g.tile,children:[jsxRuntimeExports.jsx(BodyText,{size:"medium",weight:"bold",tag:"span",children:"Point 2:"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:startCoords[1],labels:["x","y"],onChange:value=>onChange([startCoords[0],value])})]})]})};const styles$g=StyleSheet.create({tile:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8,padding:spacing.small_12,borderRadius:spacing.xSmall_8,flexDirection:"row",alignItems:"center"}});
1681
1681
 
@@ -1716,7 +1716,7 @@ const{Icon}=components;const findAndFocusElement=component=>{const DOMNode=React
1716
1716
  S3.5,9.9,3.4,9.8L2.5,8.9L0.2,6.6C0.1,6.5,0,6.3,0,6.2s0.1-0.3,0.2-0.4
1717
1717
  l0.9-0.9c0.1-0.1,0.3-0.2,0.4-0.2s0.3,0.1,0.4,0.2l1.9,1.9l4.2-4.2c0.1
1718
1718
  -0.1,0.3-0.2,0.4-0.2c0.2,0,0.3,0.1,0.4,0.2l0.9,0.9C9.9,3.5,10,3.7,
1719
- 10,3.8z`;const optionHeight=30;class Option extends React.Component{handleKeyDown(event){const{onDropdownClose}=this.props;const pressedKey=event.key;const focusedElement=event.target;if(pressedKey==="ArrowDown"&&focusedElement.nextSibling){event.preventDefault();focusedElement.nextSibling.focus();}if(pressedKey==="ArrowUp"&&focusedElement.previousSibling){event.preventDefault();focusedElement.previousSibling.focus();}if(pressedKey==="ArrowUp"&&!focusedElement.previousSibling&&onDropdownClose){event.preventDefault();onDropdownClose();}if((pressedKey==="Escape"||pressedKey==="Tab")&&onDropdownClose){onDropdownClose();}}render(){const{selected,value,onClick,children,disabled,hideFocusState,testId,ariaLabel}=this.props;return jsxRuntimeExports.jsx("button",{ref:node=>this.node=node,value:value,role:"menuitemradio","aria-checked":selected,className:css(styles$5.notAButton,disabled&&styles$5.cursorDefault,hideFocusState&&styles$5.noFocus),onClick:value=>{if(!disabled&&onClick){onClick(value);}},onKeyDown:event=>this.handleKeyDown(event),"aria-disabled":disabled,"aria-label":ariaLabel,"data-testid":testId,children:jsxRuntimeExports.jsxs("span",{className:css(styles$5.option,selected&&styles$5.optionSelected,disabled&&styles$5.optionDisabled),children:[children,selected&&jsxRuntimeExports.jsx("span",{className:css(styles$5.check),children:jsxRuntimeExports.jsx(Icon,{icon:check})})]})})}}class OptionGroup extends React.Component{componentDidMount(){if(this.focusedElement){findAndFocusElement(this.focusedElement);}}render(){const{children,onSelected,selectedValues,noMargin,onDropdownClose,hideFocusState}=this.props;return jsxRuntimeExports.jsx("div",{style:{top},className:css(styles$5.optionGroup,noMargin&&styles$5.optionGroupNoMargin),children:React.Children.map(children,(child,index)=>{const selected=selectedValues.includes(child.props.value);const reference=selected||index===0?node=>this.focusedElement=node:null;return React.cloneElement(child,{...child.props,key:index,selected:selected,onClick:()=>onSelected(child.props.value),ref:reference,onDropdownClose:onDropdownClose,hideFocusState:hideFocusState})})})}}const styles$5=StyleSheet.create({optionGroup:{margin:"4px 0"},optionGroupNoMargin:{margin:0},option:{display:"flex",flexDirection:"row",alignItems:"center",paddingLeft:32,paddingRight:32,height:optionHeight,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",color:gray17,userSelect:"none",":hover":{backgroundColor:gray95}},optionSelected:{backgroundColor:gray95,color:"#11ACCD"},optionDisabled:{color:gray76,":hover":{backgroundColor:"transparent"}},check:{position:"absolute",left:11},notAButton:{backgroundColor:"transparent",border:"none",display:"block",padding:0,margin:0,width:"100%",font:"inherit"},noFocus:{outline:"none"},cursorDefault:{cursor:"default"}});
1719
+ 10,3.8z`;const optionHeight=30;class Option extends React.Component{handleKeyDown(event){const{onDropdownClose}=this.props;const pressedKey=event.key;const focusedElement=event.currentTarget;if(pressedKey==="ArrowDown"&&focusedElement.nextElementSibling){event.preventDefault();focusedElement.nextElementSibling.focus();}if(pressedKey==="ArrowUp"&&focusedElement.previousElementSibling){event.preventDefault();focusedElement.previousElementSibling.focus();}if(pressedKey==="ArrowUp"&&!focusedElement.previousElementSibling&&onDropdownClose){event.preventDefault();onDropdownClose();}if((pressedKey==="Escape"||pressedKey==="Tab")&&onDropdownClose){onDropdownClose();}}render(){const{selected,value,onClick,children,disabled,hideFocusState,testId,ariaLabel}=this.props;return jsxRuntimeExports.jsx("button",{ref:node=>this.node=node,value:value,role:"menuitemradio","aria-checked":selected,className:css(styles$5.notAButton,disabled&&styles$5.cursorDefault,hideFocusState&&styles$5.noFocus),onClick:value=>{if(!disabled&&onClick){onClick(value);}},onKeyDown:event=>this.handleKeyDown(event),"aria-disabled":disabled,"aria-label":ariaLabel,"data-testid":testId,children:jsxRuntimeExports.jsxs("span",{className:css(styles$5.option,selected&&styles$5.optionSelected,disabled&&styles$5.optionDisabled),children:[children,selected&&jsxRuntimeExports.jsx("span",{className:css(styles$5.check),children:jsxRuntimeExports.jsx(Icon,{icon:check})})]})})}}class OptionGroup extends React.Component{componentDidMount(){if(this.focusedElement){findAndFocusElement(this.focusedElement);}}render(){const{children,onSelected,selectedValues,noMargin,onDropdownClose,hideFocusState}=this.props;return jsxRuntimeExports.jsx("div",{style:{top},className:css(styles$5.optionGroup,noMargin&&styles$5.optionGroupNoMargin),children:React.Children.map(children,(child,index)=>{const selected=selectedValues.includes(child.props.value);const reference=selected||index===0?node=>this.focusedElement=node:null;return React.cloneElement(child,{...child.props,key:index,selected:selected,onClick:()=>onSelected(child.props.value),ref:reference,onDropdownClose:onDropdownClose,hideFocusState:hideFocusState})})})}}const styles$5=StyleSheet.create({optionGroup:{margin:"4px 0"},optionGroupNoMargin:{margin:0},option:{display:"flex",flexDirection:"row",alignItems:"center",paddingLeft:32,paddingRight:32,height:optionHeight,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",color:gray17,userSelect:"none",":hover":{backgroundColor:gray95}},optionSelected:{backgroundColor:gray95,color:"#11ACCD"},optionDisabled:{color:gray76,":hover":{backgroundColor:"transparent"}},check:{position:"absolute",left:11},notAButton:{backgroundColor:"transparent",border:"none",display:"block",padding:0,margin:0,width:"100%",font:"inherit"},noFocus:{outline:"none"},cursorDefault:{cursor:"default"}});
1720
1720
 
1721
1721
  class Marker extends React.Component{componentDidMount(){document.addEventListener("click",this.handleClick,true);}UNSAFE_componentWillReceiveProps(nextProps){const{answers}=this.props;const filteredAnswers=answers.filter(answer=>nextProps.choices.includes(answer));if(JSON.stringify(answers)!==JSON.stringify(filteredAnswers)){setTimeout(()=>this.updateAnswers(filteredAnswers));}}componentWillUnmount(){document.removeEventListener("click",this.handleClick,true);}openDropdown(){this.setState({showDropdown:true});}updateAnswers(answers){const{label,onChange,x,y}=this.props;onChange({answers,label,x,y});}updateLabel(label){const{answers,onChange,x,y}=this.props;onChange({answers,label,x,y});}render(){const{answers,choices,label,onRemove,x,y}=this.props;const{showDropdown}=this.state;return jsxRuntimeExports.jsx("div",{className:css(styles$4.marker,answers.length>0&&styles$4.markerWithAnswers,showDropdown&&styles$4.markerSelected),ref:node=>this._marker=node,style:{left:`${x}%`,top:`${y}%`},title:"Click to select marker answers or to delete marker. "+"Repositioning marker is not implemented.",children:showDropdown&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("div",{className:css(styles$4.dropdownBody,styles$4.dropdownPositionWithArrow),children:[jsxRuntimeExports.jsx(Option,{value:"",onClick:()=>onRemove(),children:"Delete marker"}),jsxRuntimeExports.jsx("hr",{className:css(styles$4.dividerHorizontal)}),jsxRuntimeExports.jsx(OptionGroup,{onSelected:this.handleSelectAnswer,selectedValues:answers,children:choices.map(choice=>jsxRuntimeExports.jsx(Option,{value:choice,children:choice},choice))}),jsxRuntimeExports.jsx("div",{className:css(styles$4.labelContainer),children:jsxRuntimeExports.jsx(FormWrappedTextField$1,{placeholder:"ARIA label (for screen readers)",onChange:this.handleLabelChange,value:label,width:"100%"})})]})})})}constructor(...args){super(...args),this.state={showDropdown:false},this.handleClick=e=>{const{showDropdown}=this.state;if(this._marker===e.target){this.setState({showDropdown:!showDropdown});}else if(showDropdown){if(this._marker&&e.target instanceof Node&&!this._marker.contains(e.target)){e.stopPropagation();this.setState({showDropdown:false});}}},this.handleLabelChange=e=>{this.updateLabel(e.target.value);},this.handleSelectAnswer=toggleAnswer=>{let{answers}=this.props;if(answers.includes(toggleAnswer)){answers=answers.filter(answer=>answer!==toggleAnswer);}else {answers=[...answers,toggleAnswer];}this.updateAnswers(answers);};}}const styles$4=StyleSheet.create({marker:{position:"absolute",boxSizing:"content-box",width:16,height:16,marginLeft:-8,marginTop:-8,cursor:"pointer",background:"linear-gradient(to bottom, rgba(33, 36, 44, 0.2), rgba(33, 36, 44, 0.5))",border:"solid 2px #ffffff",borderRadius:16,boxShadow:"0 2px 10px 0 rgba(33, 36, 44, 0.1)"},markerSelected:{width:28,height:28,marginLeft:-12,marginTop:-12,border:"none",borderRadius:28,"::before":{content:"''",display:"block",width:20,height:20,marginLeft:2,marginTop:2,border:"solid 2px #ffffff",borderRadius:20}},markerWithAnswers:{background:"#1865f2"},dropdownPositionWithArrow:{left:46,bottom:-12,"::before":{content:"''",display:"block",position:"absolute",width:0,height:0,left:-16,bottom:8,borderRight:`solid 16px ${gray98}`,borderTop:"solid 16px transparent",borderBottom:"solid 16px transparent"}},labelContainer:{padding:4},dividerHorizontal:{height:0,margin:0,border:`solid ${gray85}`,borderWidth:"0 0 1px",boxShadow:"none"},dropdownBody:{position:"absolute",border:"solid 1px rgba(0, 0, 0, 0.1)",zIndex:1e3,color:gray17,backgroundColor:gray98,borderRadius:4,maxHeight:320,cursor:"pointer"}});
1722
1722