@khanacademy/perseus 43.0.0 → 43.0.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.
package/dist/es/index.js CHANGED
@@ -23,7 +23,7 @@ import { number as number$1, point, vector as vector$1, line } from '@khanacadem
23
23
  import { entries, UnreachableCaseError, keys } from '@khanacademy/wonder-stuff-core';
24
24
  import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
25
25
  import SimpleMarkdown from '@khanacademy/simple-markdown';
26
- import { pureMarkdownRules, parse as parse$4 } from '@khanacademy/pure-markdown';
26
+ import { pureMarkdownRules } from '@khanacademy/pure-markdown';
27
27
  import { TextField } from '@khanacademy/wonder-blocks-form';
28
28
  import Button from '@khanacademy/wonder-blocks-button';
29
29
  import { Strut } from '@khanacademy/wonder-blocks-layout';
@@ -31129,67 +31129,6 @@ function isUnlimitedGraphState(state) {
31129
31129
  return state.type === "point" && state.numPoints === "unlimited" || state.type === "polygon" && state.numSides === "unlimited";
31130
31130
  }
31131
31131
 
31132
- /**
31133
- * Replace all text outside of the $ TeX blocks with `\\text{...}`
31134
- * This way, the entire resulting string can be rendered within <TeX>
31135
- * and the text outside of the $ blocks will be non-TeX text.
31136
- */
31137
- function replaceOutsideTeX(mathString) {
31138
- // All the information we need is in the first section,
31139
- // whether it's typed as "blockmath" or "paragraph"
31140
- const firstSection = parse$4(mathString)[0];
31141
-
31142
- // If it's blockMath, the outer level has the full math content.
31143
- if (firstSection.type === "blockMath") {
31144
- return firstSection.content;
31145
- }
31146
-
31147
- // If it's a paragraph, we need to iterate through the sections
31148
- // to look for individual math blocks.
31149
- const condensedNodes = condenseTextNodes(firstSection.content);
31150
- let result = "";
31151
- for (const piece of condensedNodes) {
31152
- piece.type === "math" ? result += piece.content : result += `\\text{${escapeSpecialChars(piece.content)}}`;
31153
- }
31154
- return result;
31155
- }
31156
- // Helper function for replaceOutsideTeX()
31157
- // Condense adjacent text nodes into a single text node
31158
- function condenseTextNodes(nodes) {
31159
- const result = [];
31160
- if (!nodes) {
31161
- return result;
31162
- }
31163
- let currentText = "";
31164
- for (const node of nodes) {
31165
- if (node.type === "math") {
31166
- if (currentText) {
31167
- result.push({
31168
- type: "text",
31169
- content: currentText
31170
- });
31171
- currentText = "";
31172
- }
31173
- result.push(node);
31174
- } else {
31175
- currentText += node.content;
31176
- }
31177
- }
31178
- if (currentText) {
31179
- result.push({
31180
- type: "text",
31181
- content: currentText
31182
- });
31183
- }
31184
- return result;
31185
- }
31186
-
31187
- // Helper function for replaceOutsideTeX()
31188
- function escapeSpecialChars(str) {
31189
- // Escape $, \, {, and } characters
31190
- return str.replace(/([$\\{}])/g, "\\$1");
31191
- }
31192
-
31193
31132
  /**
31194
31133
  * Parse a string of text and math into a list of objects with type and content
31195
31134
  *
@@ -31221,6 +31160,29 @@ const mathOnlyParser = SimpleMarkdown.parserFor({
31221
31160
  inline: true
31222
31161
  });
31223
31162
 
31163
+ /**
31164
+ * Replace all text outside of the $ TeX blocks with `\\text{...}`
31165
+ * This way, the entire resulting string can be rendered within <TeX>
31166
+ * and the text outside of the $ blocks will be non-TeX text.
31167
+ */
31168
+ function replaceOutsideTeX(mathString) {
31169
+ // All the information we need is in the first section,
31170
+ // whether it's typed as "blockmath" or "paragraph"
31171
+ const parsed = mathOnlyParser(mathString);
31172
+ let result = "";
31173
+ for (const piece of parsed) {
31174
+ piece.type === "math" ? result += "$" + piece.content + "$" : piece.type === "specialCharacter" ? result += escapeIfUnescaped(piece.content) : result += piece.content;
31175
+ }
31176
+ return `\\text{${result}}`;
31177
+ }
31178
+ function escapeIfUnescaped(character) {
31179
+ if (character.length === 1) {
31180
+ return "\\" + character;
31181
+ } else {
31182
+ return character;
31183
+ }
31184
+ }
31185
+
31224
31186
  function AxisLabels() {
31225
31187
  const {
31226
31188
  range,
@@ -34769,6 +34731,7 @@ const MafsGraph = props => {
34769
34731
  const uniqueId = React.useId();
34770
34732
  const descriptionId = `interactive-graph-description-${uniqueId}`;
34771
34733
  const interactiveElementsDescriptionId = `interactive-graph-interactive-elements-description-${uniqueId}`;
34734
+ const unlimitedGraphKeyboardPromptId = `unlimited-graph-keyboard-prompt-${uniqueId}`;
34772
34735
  const graphRef = React.useRef(null);
34773
34736
  const {
34774
34737
  analytics
@@ -34841,7 +34804,7 @@ const MafsGraph = props => {
34841
34804
  handleKeyboardEvent(event, state, dispatch);
34842
34805
  },
34843
34806
  "aria-label": fullGraphAriaLabel,
34844
- "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId),
34807
+ "aria-describedby": describedByIds(fullGraphAriaDescription && descriptionId, interactiveElementsDescription && interactiveElementsDescriptionId, isUnlimitedGraphState(state) && "unlimited-graph-keyboard-prompt"),
34845
34808
  ref: graphRef,
34846
34809
  tabIndex: 0,
34847
34810
  onFocus: event => {
@@ -34911,6 +34874,7 @@ const MafsGraph = props => {
34911
34874
  height: height
34912
34875
  }, /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), graph)))), interactionPrompt && /*#__PURE__*/React.createElement(View, {
34913
34876
  style: {
34877
+ display: interactionPrompt ? undefined : "hidden",
34914
34878
  textAlign: "center",
34915
34879
  backgroundColor: "white",
34916
34880
  border: "1px solid #21242C52",
@@ -34922,7 +34886,9 @@ const MafsGraph = props => {
34922
34886
  top: "50%",
34923
34887
  transform: "translateY(-50%)"
34924
34888
  }
34925
- }, /*#__PURE__*/React.createElement(LabelMedium, null, strings.graphKeyboardPrompt))), renderGraphControls({
34889
+ }, /*#__PURE__*/React.createElement(LabelMedium, {
34890
+ id: unlimitedGraphKeyboardPromptId
34891
+ }, strings.graphKeyboardPrompt))), renderGraphControls({
34926
34892
  state,
34927
34893
  dispatch,
34928
34894
  width,
@@ -34985,6 +34951,10 @@ const renderPolygonGraphControls = props => {
34985
34951
  } = props;
34986
34952
  const shouldShowRemoveButton = showRemovePointButton && focusedPointIndex !== null;
34987
34953
 
34954
+ // We want to disable the closePolygon button when
34955
+ // there are not enough coords to make a polygon
34956
+ const disableCloseButton = coords.length < 3;
34957
+
34988
34958
  // If polygon is closed, show open button.
34989
34959
  // If polygon is open, show close button.
34990
34960
  const polygonButton = closedPolygon ? /*#__PURE__*/React.createElement(Button, {
@@ -35002,12 +34972,12 @@ const renderPolygonGraphControls = props => {
35002
34972
  // Conditional disable when there are less than 3 points in
35003
34973
  // the graph
35004
34974
  ,
35005
- disabled: coords.length < 3,
34975
+ disabled: disableCloseButton,
35006
34976
  style: {
35007
34977
  width: "100%",
35008
34978
  marginLeft: "20px"
35009
34979
  },
35010
- tabIndex: 0,
34980
+ tabIndex: disableCloseButton ? -1 : 0,
35011
34981
  onClick: () => {
35012
34982
  props.dispatch(actions.polygon.closePolygon());
35013
34983
  }
@@ -35895,8 +35865,12 @@ function doMovePoint(state, action) {
35895
35865
  newValue: newValue
35896
35866
  });
35897
35867
 
35898
- // Reject the move if it would cause the sides of the polygon to cross
35899
- if (polygonSidesIntersect(newCoords)) {
35868
+ // Boolean value to track whether we can let the polygon sides interact.
35869
+ // They can interact if it's an unlimited polygon that is open.
35870
+ const polygonSidesCanIntersect = state.numSides === "unlimited" && !state.closedPolygon;
35871
+
35872
+ // Reject the move if it would cause the sides of the polygon to cross.
35873
+ if (!polygonSidesCanIntersect && polygonSidesIntersect(newCoords)) {
35900
35874
  return state;
35901
35875
  }
35902
35876
  return _extends({}, state, {
@@ -44784,7 +44758,7 @@ const init = function init() {
44784
44758
 
44785
44759
  // This file is processed by a Rollup plugin (replace) to inject the production
44786
44760
  const libName = "@khanacademy/perseus";
44787
- const libVersion = "43.0.0";
44761
+ const libVersion = "43.0.1";
44788
44762
  addLibraryVersionToPerseusDebug(libName, libVersion);
44789
44763
 
44790
44764
  const apiVersion = {