@khanacademy/perseus 33.0.0 → 33.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -8673,10 +8673,10 @@ var Raphael$1 = (function () {
8673
8673
  * provided on KhanUtil.
8674
8674
  */
8675
8675
  const KhanColors = {
8676
- BLUE: "#6495ED",
8676
+ BLUE: color.blue,
8677
8677
  ORANGE: "#FFA500",
8678
8678
  PINK: "#FF00AF",
8679
- GREEN: "#28AE7B",
8679
+ GREEN: color.green,
8680
8680
  PURPLE: "#9D38BD",
8681
8681
  RED: "#DF0030",
8682
8682
  GRAY: "gray",
@@ -8752,11 +8752,9 @@ const KhanColors = {
8752
8752
  // of any redesigns.
8753
8753
  _BACKGROUND: "#FDFDFD",
8754
8754
  // TODO(eater): Get rid of this altogether.
8755
- INTERACTING: "#71B307",
8756
- // KA_GREEN
8757
- INTERACTIVE: "#71B307",
8758
- // KA_GREEN
8759
- DYNAMIC: "#6495ED" // BLUE
8755
+ INTERACTING: color.green,
8756
+ INTERACTIVE: color.green,
8757
+ DYNAMIC: color.blue
8760
8758
  };
8761
8759
 
8762
8760
  // DrawingTransform is responsible for transforming from "math coordinates"
@@ -10036,21 +10034,50 @@ const setLabelMargins = function setLabelMargins(span, size) {
10036
10034
  });
10037
10035
  } else {
10038
10036
  var _$container$css, _$container$width, _$span$css;
10039
- const $container = $span.closest(".svg-image");
10037
+ // We are using jQuery to collect information and calculate a scale
10038
+ // since we don't have a way to pass it to this function.
10039
+ // We need the width of the container in order to calculate the scale to apply to the label.
10040
+ // Unfortunately, the DOM tree leading to the label is not consistent.
10041
+ // Therefore, we need to check different elements and different style properties to get the width of the container.
10042
+ // Some graphie labels exist within an ".svg-image" container, and others do not.
10043
+ // All graphie labels have a ".graphie" container.
10044
+ // When a label has an ".svg-image" container,
10045
+ // the width information in the ".graphie" element is expressed as a percentage instead of pixels,
10046
+ // so we can't use it.
10047
+ // Instead, the ".svg-image" container can be used to get the width information.
10048
+ // The following lines determine which container element to use for the width measurement.
10049
+ const $svgImage = $span.closest(".svg-image");
10050
+ const $graphie = $span.closest(".graphie");
10051
+ // If an ".svg-image" container exists in the DOM tree, then use it, otherwise use the ".graphie" container.
10052
+ const $container = $svgImage.length > 0 ? $svgImage : $graphie;
10053
+
10040
10054
  // Ensuring that the line-height of the text doesn't throw off placement of the text element.
10041
10055
  // Inherited line-height values can really mess up placement.
10042
10056
  $container.css("line-height", "normal");
10043
10057
 
10044
- // The 'max-width' value is the same as the expected (100% scale) width of the graphie.
10045
- // We are using jQuery to get this information since we don't have a way to pass it to this function.
10046
- const expectedWidth = (_$container$css = $container.css("max-width")) != null ? _$container$css : "0px";
10058
+ // The expected width of the graphie is found in the "max-width" property on ".svg-image" containers,
10059
+ // and is found in the "width" property on ".graphie" containers.
10060
+ const widthValues = (_$container$css = $container.css(["max-width", "width"])) != null ? _$container$css : {
10061
+ // The browser will always return a value, but tests won't, so ensuring something is returned.
10062
+ "max-width": "0px"
10063
+ };
10064
+ const expectedWidth =
10065
+ // Verified in Chrome, Firefox, and Safari - all return the same "none" value if the property does not exist.
10066
+ widthValues["max-width"] !== "none" ? widthValues["max-width"] : widthValues["width"];
10047
10067
  // We can calculate the true scale of the graphie by taking actual width and dividing by the expected width.
10048
- // NOTE: Using 'slice' to remove the "px" unit from the end of the expected width value.
10049
- const scale = ((_$container$width = $container.width()) != null ? _$container$width : 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10068
+ // NOTE: Using 'replace' to remove the "px" unit from the end of the expected width value.
10069
+ let scale = ((_$container$width = $container.width()) != null ? _$container$width : 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10070
+ // If something failed in the calculation, then default to 100% scale.
10071
+ if (isNaN(scale)) {
10072
+ scale = 100;
10073
+ } else if (scale === 0) {
10074
+ scale = 100;
10075
+ }
10050
10076
 
10051
10077
  // Any padding needs to be scaled accordingly.
10052
- const currentPadding = (_$span$css = $span.css("padding")) != null ? _$span$css : "0px";
10053
- const newPadding = Math.round(parseInt(currentPadding.slice(0, -2)) * scale) / 100;
10078
+ const padding = (_$span$css = $span.css("padding")) != null ? _$span$css : "0px";
10079
+ const currentPadding = padding !== "none" ? padding : "0px";
10080
+ const newPadding = Math.round(parseInt(currentPadding.replace(/px$/, "")) * scale) / 100;
10054
10081
 
10055
10082
  // "multipliers" basically move the position of the text by using 1, 0, -1
10056
10083
  // 'margin-left' and 'margin-top' are used to position the text.
@@ -28320,6 +28347,94 @@ Graph.defaultProps = {
28320
28347
  isMobile: false
28321
28348
  };
28322
28349
 
28350
+ function pathBuilder() {
28351
+ return new PathBuilder();
28352
+ }
28353
+ class PathBuilder {
28354
+ constructor() {
28355
+ this.path = [];
28356
+ this.scaleFactor = 1;
28357
+ }
28358
+ build() {
28359
+ return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
28360
+ }
28361
+
28362
+ // add a move (M) command to the path
28363
+ move(x, y) {
28364
+ this.path.push({
28365
+ action: "M",
28366
+ args: [x, y]
28367
+ });
28368
+ return this;
28369
+ }
28370
+ line(x, y) {
28371
+ this.path.push({
28372
+ action: "L",
28373
+ args: [x, y]
28374
+ });
28375
+ return this;
28376
+ }
28377
+ circularArc(radius, toX, toY, {
28378
+ sweep = false,
28379
+ largeArc = false
28380
+ } = {}) {
28381
+ this.path.push({
28382
+ action: "A",
28383
+ args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
28384
+ });
28385
+ return this;
28386
+ }
28387
+
28388
+ // add a curve (C) command to the path
28389
+ curve(control1X, control1Y, control2X, control2Y, endX, endY) {
28390
+ this.path.push({
28391
+ action: "C",
28392
+ args: [control1X, control1Y, control2X, control2Y, endX, endY]
28393
+ });
28394
+ return this;
28395
+ }
28396
+
28397
+ // Scale all coordinates of the path by a factor
28398
+ scale(factor) {
28399
+ this.scaleFactor *= factor;
28400
+ return this;
28401
+ }
28402
+ }
28403
+ function commandToString(command) {
28404
+ return `${command.action}${command.args.join(" ")}`;
28405
+ }
28406
+ function scaleCommandBy(scaleFactor) {
28407
+ return command => {
28408
+ switch (command.action) {
28409
+ case "A":
28410
+ // TODO(benchristel): do we want to refactor this switch to
28411
+ // use polymorphism?
28412
+ // Arc command
28413
+ return _extends({}, command, {
28414
+ args: [command.args[0] * scaleFactor,
28415
+ // x radius
28416
+ command.args[1] * scaleFactor,
28417
+ // y radius
28418
+ command.args[2],
28419
+ // rotation
28420
+ command.args[3],
28421
+ // largeArc flag
28422
+ command.args[4],
28423
+ // sweep flag
28424
+ command.args[5] * scaleFactor,
28425
+ // end x
28426
+ command.args[6] * scaleFactor // end y
28427
+ ]
28428
+ });
28429
+
28430
+ default:
28431
+ return _extends({}, command, {
28432
+ args: command.args.map(c => c * scaleFactor)
28433
+ });
28434
+ }
28435
+ };
28436
+ }
28437
+
28323
28438
  // Restricts `value` to be between `min` and `max`.
28324
28439
  function clamp(value, min, max) {
28325
28440
  if (value < min) {
@@ -28536,377 +28651,6 @@ function pixelsToVectors(pixels, graphState) {
28536
28651
  });
28537
28652
  }
28538
28653
 
28539
- function AxisLabels() {
28540
- const {
28541
- range,
28542
- labels,
28543
- width,
28544
- height
28545
- } = useGraphConfig();
28546
- const yAxisLabelLocation = [0, range[Y][MAX]];
28547
- const xAxisLabelLocation = [range[X][MAX], 0];
28548
- const [xAxisLabelText, yAxisLabelText] = labels;
28549
- const graphInfo = {
28550
- range,
28551
- width,
28552
- height
28553
- };
28554
- const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
28555
- // The default location for the y-axis-label is at the maximum y point
28556
- // This is just underneath the tick line for that point. The -24 moves the
28557
- // label up one grid square, so it sits on top of the graph
28558
- const [x2, y2] = vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
28559
- const {
28560
- TeX
28561
- } = getDependencies();
28562
- return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
28563
- style: {
28564
- position: "absolute",
28565
- left: x1,
28566
- top: y1,
28567
- fontSize: "14px",
28568
- transform: "translate(7px, -50%)"
28569
- }
28570
- }, /*#__PURE__*/React__default.createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default.createElement("span", {
28571
- style: {
28572
- position: "absolute",
28573
- left: x2,
28574
- top: y2,
28575
- fontSize: "14px",
28576
- transform: "translate(-50%, 0px)"
28577
- }
28578
- }, /*#__PURE__*/React__default.createElement(TeX, null, yAxisLabelText)));
28579
- }
28580
-
28581
- // Universal padding for the axis ticks to ensure that the labels
28582
- // have enough space to render without overlapping the tick lines
28583
- const tickPadding = 5;
28584
- const AxisTickLabels = () => {
28585
- const graphConfig = useGraphConfig();
28586
- const {
28587
- tickStep,
28588
- range
28589
- } = graphConfig;
28590
- const [[xMin, xMax], [yMin, yMax]] = range;
28591
- const [xTickStep, yTickStep] = tickStep;
28592
- const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
28593
- const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
28594
- return /*#__PURE__*/React.createElement("div", {
28595
- className: "axis-tick-labels"
28596
- }, /*#__PURE__*/React.createElement(YGridAxis, {
28597
- axisTicks: yGridTicks,
28598
- graphConfig: graphConfig
28599
- }), /*#__PURE__*/React.createElement(XGridAxis, {
28600
- axisTicks: xGridTicks,
28601
- graphConfig: graphConfig
28602
- }));
28603
- };
28604
-
28605
- // Generate the necessary styles and ticks for the y-axis tick labels container
28606
- const YGridAxis = props => {
28607
- const {
28608
- axisTicks,
28609
- graphConfig
28610
- } = props;
28611
- const {
28612
- width,
28613
- height
28614
- } = graphConfig;
28615
-
28616
- // First get the label height by calculating the difference between the first two y-axis labels
28617
- const yTopPoint = pointToPixel([0, axisTicks[0]], graphConfig);
28618
- const ySecondPoint = pointToPixel([0, axisTicks[1]], graphConfig);
28619
- const yLabelHeight = ySecondPoint[1] - yTopPoint[1];
28620
-
28621
- // When rendering purely positive y-axis labels, we want to adjust the left position
28622
- // from the lowest calculated tick, as yMin may be negative
28623
- const yLowestTick = axisTicks[axisTicks.length - 1];
28624
- const yLeftAdjustment = Math.min(Math.max(yTopPoint[0] - tickPadding, 0), width);
28625
-
28626
- // We only want to render the 0 label on the y-axis if it is left of the grid
28627
- const yAxisIsLeftOfGrid = yLeftAdjustment === 0;
28628
-
28629
- // If the y-axis is right of the graph's viewbox/range,
28630
- // we want to adjust both the positioning and text alignment
28631
- const yAxisRightOfGrid = yLeftAdjustment === width;
28632
-
28633
- // Determine the default spacing for the labels based on whether the y-axis is right of the grid
28634
- const defaultSpacing = yAxisRightOfGrid ? 0.5 : 0;
28635
-
28636
- // We also want to adjust the spacing if there are no negative y-axis labels as the extra space is not needed
28637
- const marginSpacing = yLowestTick >= 0 ? defaultSpacing * 2 : defaultSpacing;
28638
-
28639
- // Determine the text alignment based on whether the y-axis is right of the grid
28640
- // We need to cast this as a const as it is used in the inline styles
28641
- const textAlign = yAxisRightOfGrid ? "left" : "right";
28642
- const yAxisStyles = {
28643
- left: `calc(${yLeftAdjustment}px - ${marginSpacing}em)`,
28644
- top: `calc(${yTopPoint[1]}px - 0.5em)`,
28645
- height,
28646
- textAlign,
28647
- "--y-axis-label-height": yLabelHeight + "px"
28648
- };
28649
- const classNames = yAxisRightOfGrid ? "y-axis-tick-labels y-axis-right-of-grid" : "y-axis-tick-labels ";
28650
- return /*#__PURE__*/React.createElement("div", {
28651
- className: classNames,
28652
- "data-testid": "y-axis-tick-labels",
28653
- style: yAxisStyles
28654
- }, axisTicks.map(label => {
28655
- return /*#__PURE__*/React.createElement(AxisTickLabel, {
28656
- label: label,
28657
- axis: "y",
28658
- key: `y-grid-tick-${label}`,
28659
- graphConfig: graphConfig,
28660
- axisOutOfBounds: yAxisIsLeftOfGrid
28661
- });
28662
- }));
28663
- };
28664
-
28665
- // Generate the necessary styles and ticks for the x-axis tick labels container
28666
- const XGridAxis = props => {
28667
- const {
28668
- axisTicks,
28669
- graphConfig
28670
- } = props;
28671
- const {
28672
- width,
28673
- height
28674
- } = graphConfig;
28675
-
28676
- // Determine label width by calculating the difference between the first two x-axis labels
28677
- const xFirstPoint = pointToPixel([axisTicks[0], 0], graphConfig);
28678
- const xSecondPoint = pointToPixel([axisTicks[1], 0], graphConfig);
28679
- const xLabelWidth = Math.abs(xSecondPoint[0] - xFirstPoint[0]);
28680
-
28681
- // Determine the top position of the x-axis labels based on
28682
- // whether the x-axis is above, within, or below the graph
28683
- const xAxisAboveGraph = xFirstPoint[1] < 0;
28684
- const xTopAdjustment = xAxisAboveGraph ? 0 : Math.min(xFirstPoint[1] + tickPadding, height);
28685
-
28686
- // Determine whether the x-axis is outside of the graph's viewbox/range
28687
- // This is used to conditionally render the 0 label on the x-axis
28688
- const xAxisOutOfBounds = xTopAdjustment === height || xAxisAboveGraph;
28689
-
28690
- // Determine the available space to the right of the x-axis labels
28691
- const availableSpaceRight = width - xFirstPoint[0];
28692
-
28693
- // Calculate the total combined width of ALL the x-axis labels
28694
- const axisTicksWidth = axisTicks.length * xLabelWidth;
28695
-
28696
- // Determine if we need to increase the width of the axis past the graph width
28697
- const calculatedWidth = axisTicksWidth > width ? axisTicksWidth : width;
28698
-
28699
- // Determine the right adjustment for the x-axis labels based on the available space
28700
- // We're adjusting the right as the flex-direction is row-reverse
28701
- const xRightAdjustment = availableSpaceRight - xLabelWidth / 2;
28702
- const xAxisStyles = {
28703
- top: xTopAdjustment,
28704
- right: xRightAdjustment,
28705
- width: calculatedWidth,
28706
- "--x-axis-label-width": xLabelWidth + "px"
28707
- };
28708
- return /*#__PURE__*/React.createElement("div", {
28709
- className: `x-axis-tick-labels ${xAxisAboveGraph && "x-axis-top-of-grid"}`,
28710
- "data-testid": "x-axis-tick-labels",
28711
- style: xAxisStyles
28712
- }, axisTicks.map(label => {
28713
- return /*#__PURE__*/React.createElement(AxisTickLabel, {
28714
- axis: "x",
28715
- label: label,
28716
- key: `x-grid-tick-${label}`,
28717
- graphConfig: graphConfig,
28718
- axisOutOfBounds: xAxisOutOfBounds
28719
- });
28720
- }));
28721
- };
28722
-
28723
- // Generate the individual tick label elements
28724
- const AxisTickLabel = ({
28725
- label,
28726
- graphConfig,
28727
- axisOutOfBounds,
28728
- axis
28729
- }) => {
28730
- const {
28731
- gridStep,
28732
- tickStep
28733
- } = graphConfig;
28734
- // Determine the point on the axis based on the axis type
28735
- const pointOnAxis = axis === "x" ? [label, 0] : [0, label];
28736
- const pixelPoint = pointToPixel(pointOnAxis, graphConfig);
28737
-
28738
- // Determine the relevant edge of the graph based on the axis type
28739
- const graphEdge = axis === "x" ? graphConfig.width : graphConfig.height;
28740
-
28741
- // Determine the vector index based on the axis type
28742
- const vectorIndex = axis === "x" ? 0 : 1;
28743
-
28744
- // Determine whether or not to render the tick label text
28745
- const shouldShowLabel = showTickLabel({
28746
- label,
28747
- axisOutOfBounds,
28748
- graphEdge,
28749
- position: pixelPoint[vectorIndex],
28750
- gridStep: gridStep[vectorIndex],
28751
- tickStep: tickStep[vectorIndex]
28752
- });
28753
- return /*#__PURE__*/React.createElement("span", {
28754
- className: `${axis}-axis-tick-label`
28755
- }, shouldShowLabel && label);
28756
- };
28757
-
28758
- // Determine whether or not to show the tick label text
28759
- const showTickLabel = ({
28760
- gridStep,
28761
- tickStep,
28762
- label,
28763
- graphEdge,
28764
- position,
28765
- axisOutOfBounds
28766
- }) => {
28767
- let showLabel = true;
28768
-
28769
- // We only want to show the initial negative tick labels (e.g. -1) on each
28770
- // axis if the tickStep > gridStep, to ensure that these labels do not overlap.
28771
- // e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
28772
- // which allows enough room for both these tick labels to render.
28773
- showLabel = tickStep > gridStep ? true : label !== -tickStep;
28774
-
28775
- // If the tick label position is greater than the relevant edge of the graph, don't render it
28776
- if (position <= -graphEdge || position >= graphEdge) {
28777
- showLabel = false;
28778
- }
28779
-
28780
- // If the label is 0, we only want to show it if the axis is to the left of the graph's viewbox/range
28781
- // otherwise it will overlap with graph axis labels
28782
- if (label === 0 && !axisOutOfBounds) {
28783
- showLabel = false;
28784
- }
28785
- return showLabel;
28786
- };
28787
-
28788
- // Generate the tick labels for an axis based on the tick step
28789
- function generateTickLocations$1(tickStep, min, max) {
28790
- const positiveTicks = [];
28791
- const negativeTicks = [];
28792
- const ticks = [];
28793
-
28794
- // Add 0 if it is applicable.
28795
- // This will be conditionally rendered using showTickLabel.
28796
- if (min <= 0 && max >= 0) {
28797
- positiveTicks.push(0);
28798
- }
28799
-
28800
- // Add ticks on the positive axis
28801
- // Start at the first tick after 0 or the minimum value,
28802
- // taking into account that the graph may be zoomed in on the positive axis
28803
- let i = Math.max(min, 0) + tickStep;
28804
- for (i; min < i && i < max; i += tickStep) {
28805
- positiveTicks.push(i);
28806
- }
28807
-
28808
- // Add ticks on the negative axis
28809
- // Start at the first tick before 0 or the maximum value,
28810
- // taking into account that the graph may be zoomed in on the negative axis
28811
- i = Math.min(max, 0) - tickStep;
28812
- for (i; i > min; i -= tickStep) {
28813
- negativeTicks.push(i);
28814
- }
28815
-
28816
- // Reverse the ticks so that they are in the correct render order
28817
- positiveTicks.reverse();
28818
- ticks.push(...positiveTicks, ...negativeTicks);
28819
- return ticks;
28820
- }
28821
-
28822
- function pathBuilder() {
28823
- return new PathBuilder();
28824
- }
28825
- class PathBuilder {
28826
- constructor() {
28827
- this.path = [];
28828
- this.scaleFactor = 1;
28829
- }
28830
- build() {
28831
- return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
28832
- }
28833
-
28834
- // add a move (M) command to the path
28835
- move(x, y) {
28836
- this.path.push({
28837
- action: "M",
28838
- args: [x, y]
28839
- });
28840
- return this;
28841
- }
28842
- line(x, y) {
28843
- this.path.push({
28844
- action: "L",
28845
- args: [x, y]
28846
- });
28847
- return this;
28848
- }
28849
- circularArc(radius, toX, toY, {
28850
- sweep = false,
28851
- largeArc = false
28852
- } = {}) {
28853
- this.path.push({
28854
- action: "A",
28855
- args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
28856
- });
28857
- return this;
28858
- }
28859
-
28860
- // add a curve (C) command to the path
28861
- curve(control1X, control1Y, control2X, control2Y, endX, endY) {
28862
- this.path.push({
28863
- action: "C",
28864
- args: [control1X, control1Y, control2X, control2Y, endX, endY]
28865
- });
28866
- return this;
28867
- }
28868
-
28869
- // Scale all coordinates of the path by a factor
28870
- scale(factor) {
28871
- this.scaleFactor *= factor;
28872
- return this;
28873
- }
28874
- }
28875
- function commandToString(command) {
28876
- return `${command.action}${command.args.join(" ")}`;
28877
- }
28878
- function scaleCommandBy(scaleFactor) {
28879
- return command => {
28880
- switch (command.action) {
28881
- case "A":
28882
- // TODO(benchristel): do we want to refactor this switch to
28883
- // use polymorphism?
28884
- // Arc command
28885
- return _extends({}, command, {
28886
- args: [command.args[0] * scaleFactor,
28887
- // x radius
28888
- command.args[1] * scaleFactor,
28889
- // y radius
28890
- command.args[2],
28891
- // rotation
28892
- command.args[3],
28893
- // largeArc flag
28894
- command.args[4],
28895
- // sweep flag
28896
- command.args[5] * scaleFactor,
28897
- // end x
28898
- command.args[6] * scaleFactor // end y
28899
- ]
28900
- });
28901
-
28902
- default:
28903
- return _extends({}, command, {
28904
- args: command.args.map(c => c * scaleFactor)
28905
- });
28906
- }
28907
- };
28908
- }
28909
-
28910
28654
  // We use the pathBuilder here to scale up the SVG path coordinates used
28911
28655
  // elsewhere for arrowheads. We scale in the path itself instead of using a CSS
28912
28656
  // transform because a transform would also scale up the stroke weight, and we
@@ -28937,7 +28681,10 @@ function AxisArrows() {
28937
28681
  range: [[xMin, xMax], [yMin, yMax]]
28938
28682
  } = useGraphConfig();
28939
28683
  const axisColor = "var(--mafs-fg)";
28940
- return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
28684
+
28685
+ // Only render the arrows if the axis is within the visible range
28686
+ // as otherwise the arrows will be rendered outside the graph
28687
+ return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, !(yMin > 0 || yMax < 0) && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
28941
28688
  color: axisColor,
28942
28689
  tip: [xMin, 0],
28943
28690
  angle: 180
@@ -28945,7 +28692,7 @@ function AxisArrows() {
28945
28692
  color: axisColor,
28946
28693
  tip: [xMax, 0],
28947
28694
  angle: 0
28948
- }), /*#__PURE__*/React__default.createElement(Arrowhead, {
28695
+ })), !(xMin > 0 || xMax < 0) && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Arrowhead, {
28949
28696
  color: axisColor,
28950
28697
  tip: [0, yMin],
28951
28698
  angle: 90
@@ -28953,38 +28700,75 @@ function AxisArrows() {
28953
28700
  color: axisColor,
28954
28701
  tip: [0, yMax],
28955
28702
  angle: 270
28956
- }));
28703
+ })));
28957
28704
  }
28958
28705
 
28706
+ function AxisLabels() {
28707
+ const {
28708
+ range,
28709
+ labels,
28710
+ width,
28711
+ height
28712
+ } = useGraphConfig();
28713
+ const yAxisLabelLocation = [0, range[Y][MAX]];
28714
+ const xAxisLabelLocation = [range[X][MAX], 0];
28715
+ const [xAxisLabelText, yAxisLabelText] = labels;
28716
+ const graphInfo = {
28717
+ range,
28718
+ width,
28719
+ height
28720
+ };
28721
+ const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
28722
+ // The default location for the y-axis-label is at the maximum y point
28723
+ // This is just underneath the tick line for that point. The -24 moves the
28724
+ // label up one grid square, so it sits on top of the graph
28725
+ const [x2, y2] = vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
28726
+ const {
28727
+ TeX
28728
+ } = getDependencies();
28729
+ return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("span", {
28730
+ style: {
28731
+ position: "absolute",
28732
+ left: x1,
28733
+ top: y1,
28734
+ fontSize: "14px",
28735
+ transform: "translate(7px, -50%)"
28736
+ }
28737
+ }, /*#__PURE__*/React__default.createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default.createElement("span", {
28738
+ style: {
28739
+ position: "absolute",
28740
+ left: x2,
28741
+ top: y2,
28742
+ fontSize: "14px",
28743
+ transform: "translate(-50%, 0px)"
28744
+ }
28745
+ }, /*#__PURE__*/React__default.createElement(TeX, null, yAxisLabelText)));
28746
+ }
28747
+
28748
+ // The size of the ticks and labels in pixels
28959
28749
  const tickSize = 10;
28960
- const tickStyle = {
28961
- stroke: "black",
28962
- strokeWidth: 1
28963
- };
28750
+ const tickLabelSize = 14;
28964
28751
  const YGridTick = ({
28965
28752
  y,
28966
- graphInfo
28753
+ range
28967
28754
  }) => {
28755
+ // If the graph requires out-of-bounds labels, we want to make sure to set the
28756
+ // coordinates to the edge of the visible range of the graph. Otherwise,
28757
+ // the ticks and labels would render outside of the clipping-mask.
28968
28758
  let xPointOnAxis = 0;
28969
-
28970
- // If the graph is zoomed in, we want to make sure the ticks are still visible
28971
- // even if they are outside the graph's range.
28972
- if (graphInfo.range[X][MIN] > 0) {
28759
+ if (range[X][MIN] > 0) {
28973
28760
  // If the graph is on the positive side of the x-axis, lock the ticks to the left side of the graph
28974
- xPointOnAxis = graphInfo.range[X][MIN];
28761
+ xPointOnAxis = range[X][MIN];
28975
28762
  }
28976
- if (graphInfo.range[X][MAX] < 0) {
28763
+ if (range[X][MAX] < 0) {
28977
28764
  // If the graph is on the negative side of the x-axis, lock the ticks to the right side of the graph
28978
- xPointOnAxis = graphInfo.range[X][MAX];
28765
+ xPointOnAxis = range[X][MAX];
28979
28766
  }
28767
+
28768
+ // Convert the Vector2 coordinates to pixel coordinates
28980
28769
  const pointOnAxis = [xPointOnAxis, y];
28981
28770
  const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
28982
28771
 
28983
- // If the tick is on the edge of the graph's range, don't render it
28984
- if (yPosition === -graphInfo.height || yPosition === graphInfo.height + 20) {
28985
- return null;
28986
- }
28987
-
28988
28772
  // Position of the start of the tick
28989
28773
  const x1 = xPosition - tickSize / 2;
28990
28774
  const y1 = yPosition;
@@ -28992,39 +28776,55 @@ const YGridTick = ({
28992
28776
  // Position of the end of the tick
28993
28777
  const x2 = xPosition + tickSize / 2;
28994
28778
  const y2 = yPosition;
28779
+
28780
+ // Adjust the y position of the x-axis labels based on
28781
+ // whether the x-axis is above, within, or below the graph
28782
+ const xAdjustment = range[X][MAX] <= 0 ? tickLabelSize * 1.5 : -tickLabelSize * 1.1;
28783
+ const xPositionText = xPosition + xAdjustment;
28784
+ const yPositionText = yPosition + tickLabelSize * 0.25; // Center the text vertically on the tick
28785
+
28786
+ // If the graph displays both the y and x axis lines within the graph, we want
28787
+ // to hide the label at -1 on the y-axis to prevent overlap with the x-axis label
28788
+ const showLabel = shouldShowLabel(y, range);
28995
28789
  return /*#__PURE__*/React.createElement("g", {
28996
- className: "y-axis-ticks"
28790
+ className: "tick"
28997
28791
  }, /*#__PURE__*/React.createElement("line", {
28998
28792
  x1: x1,
28999
28793
  y1: y1,
29000
28794
  x2: x2,
29001
28795
  y2: y2,
29002
- style: tickStyle
29003
- }));
28796
+ className: "axis-tick"
28797
+ }), showLabel && /*#__PURE__*/React.createElement("text", {
28798
+ className: "axis-tick-label",
28799
+ style: {
28800
+ fontSize: tickLabelSize
28801
+ },
28802
+ textAnchor: "end",
28803
+ x: xPositionText,
28804
+ y: yPositionText
28805
+ }, y.toString()));
29004
28806
  };
29005
28807
  const XGridTick = ({
29006
28808
  x,
29007
- graphInfo
28809
+ range
29008
28810
  }) => {
28811
+ // If the graph requires out-of-bounds labels, we want to make sure to set the
28812
+ // coordinates to the edge of the visible range of the graph. Otherwise,
28813
+ // the ticks and labels would render outside of the clipping-mask.
29009
28814
  let yPointOnAxis = 0;
29010
- // If the graph is zoomed in, we want to make sure the ticks are still visible
29011
- // even if they are outside the graph's range.
29012
- if (graphInfo.range[Y][MIN] > 0) {
28815
+ if (range[Y][MIN] > 0) {
29013
28816
  // If the graph is on the positive side of the y-axis, lock the ticks to the top of the graph
29014
- yPointOnAxis = graphInfo.range[Y][MIN];
28817
+ yPointOnAxis = range[Y][MIN];
29015
28818
  }
29016
- if (graphInfo.range[Y][MAX] < 0) {
28819
+ if (range[Y][MAX] < 0) {
29017
28820
  // If the graph is on the negative side of the x-axis, lock the ticks to the bottom of the graph
29018
- yPointOnAxis = graphInfo.range[Y][MAX];
28821
+ yPointOnAxis = range[Y][MAX];
29019
28822
  }
28823
+
28824
+ // Convert the Vector2 coordinates to pixel coordinates
29020
28825
  const pointOnAxis = [x, yPointOnAxis];
29021
28826
  const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
29022
28827
 
29023
- // If the tick is on the edge of the graph's range, don't render it
29024
- if (xPosition === -graphInfo.width / 2 || xPosition === graphInfo.width) {
29025
- return null;
29026
- }
29027
-
29028
28828
  // Position of the start of the tick
29029
28829
  const x1 = xPosition;
29030
28830
  const y1 = yPosition + tickSize / 2;
@@ -29032,21 +28832,56 @@ const XGridTick = ({
29032
28832
  // Position of the end of the tick
29033
28833
  const x2 = xPosition;
29034
28834
  const y2 = yPosition - tickSize / 2;
28835
+
28836
+ // Adjust the Y position of the x-axis labels based on
28837
+ // whether the x-axis is above, within, or below the graph
28838
+ const yAdjustment = range[Y][MAX] < 0 ? -tickLabelSize : tickLabelSize * 1.75;
28839
+
28840
+ // Adjust the X position of the x-axis labels based on
28841
+ // whether the label is positive or negative, in order to
28842
+ // account for the width of the negative sign
28843
+ const xAdjustment = x < 0 ? -2 : 0;
28844
+
28845
+ // Apply the adjustments to the x and y positions for the text
28846
+ const xPositionText = xPosition + xAdjustment;
28847
+ const yPositionText = yPosition + yAdjustment;
29035
28848
  return /*#__PURE__*/React.createElement("g", {
29036
- className: "x-axis-ticks"
28849
+ className: "tick"
29037
28850
  }, /*#__PURE__*/React.createElement("line", {
29038
28851
  x1: x1,
29039
28852
  y1: y1,
29040
28853
  x2: x2,
29041
28854
  y2: y2,
29042
- style: tickStyle
29043
- }));
28855
+ className: "axis-tick"
28856
+ }), /*#__PURE__*/React.createElement("text", {
28857
+ className: "axis-tick-label",
28858
+ style: {
28859
+ fontSize: tickLabelSize
28860
+ },
28861
+ textAnchor: "middle",
28862
+ x: xPositionText,
28863
+ y: yPositionText
28864
+ }, x.toString()));
28865
+ };
28866
+
28867
+ // Determines whether to show the label for the given tick
28868
+ // Currently, the only condition is to hide the label at -1
28869
+ // on the y-axis when the x-axis is within the graph
28870
+ const shouldShowLabel = (number, range) => {
28871
+ let showLabel = true;
28872
+
28873
+ // If the x-axis is within the graph and the y-axis is at -1, hide the label
28874
+ if (range[X][MIN] < -1 && range[X][MAX] > 0 && number === -1) {
28875
+ showLabel = false;
28876
+ }
28877
+ return showLabel;
29044
28878
  };
29045
28879
  function generateTickLocations(tickStep, min, max) {
29046
28880
  const ticks = [];
29047
28881
 
29048
28882
  // Add ticks in the positive direction
29049
- for (let _i = 0 + tickStep; _i < max; _i += tickStep) {
28883
+ const start = Math.max(min, 0);
28884
+ for (let _i = start + tickStep; _i < max; _i += tickStep) {
29050
28885
  ticks.push(_i);
29051
28886
  }
29052
28887
 
@@ -29061,34 +28896,34 @@ function generateTickLocations(tickStep, min, max) {
29061
28896
  const AxisTicks = () => {
29062
28897
  const {
29063
28898
  tickStep,
29064
- range,
29065
- width,
29066
- height
28899
+ range
29067
28900
  } = useGraphConfig();
29068
- const graphInfo = {
29069
- range,
29070
- width,
29071
- height
29072
- };
29073
28901
  const [[xMin, xMax], [yMin, yMax]] = range;
29074
28902
  const [xTickStep, yTickStep] = tickStep;
28903
+
28904
+ // Generate the tick locations & labels for the x and y axes
29075
28905
  const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
29076
28906
  const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
29077
28907
  return /*#__PURE__*/React.createElement("g", {
29078
- className: "axis-ticks"
28908
+ className: "axis-ticks",
28909
+ role: "presentation"
28910
+ }, /*#__PURE__*/React.createElement("g", {
28911
+ className: "y-axis-ticks"
29079
28912
  }, yGridTicks.map(y => {
29080
28913
  return /*#__PURE__*/React.createElement(YGridTick, {
29081
28914
  y: y,
29082
28915
  key: `y-grid-tick-${y}`,
29083
- graphInfo: graphInfo
28916
+ range: range
29084
28917
  });
29085
- }), xGridTicks.map(x => {
28918
+ })), /*#__PURE__*/React.createElement("g", {
28919
+ className: "x-axis-ticks"
28920
+ }, xGridTicks.map(x => {
29086
28921
  return /*#__PURE__*/React.createElement(XGridTick, {
29087
28922
  x: x,
29088
28923
  key: `x-grid-tick-${x}`,
29089
- graphInfo: graphInfo
28924
+ range: range
29090
28925
  });
29091
- }));
28926
+ })));
29092
28927
  };
29093
28928
 
29094
28929
  /**
@@ -29109,12 +28944,10 @@ const axisOptions = (props, axisIndex) => {
29109
28944
  };
29110
28945
  };
29111
28946
  const Grid = props => {
29112
- return props.markings === "none" ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
28947
+ return props.markings === "none" ? null : /*#__PURE__*/React.createElement(Coordinates.Cartesian, {
29113
28948
  xAxis: axisOptions(props, X),
29114
28949
  yAxis: axisOptions(props, Y)
29115
- }),
29116
- // Only render the axis ticks and arrows if the markings are set to a full "graph"
29117
- props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisTicks, null), /*#__PURE__*/React.createElement(AxisArrows, null)));
28950
+ });
29118
28951
  };
29119
28952
 
29120
28953
  // Displays a stylized open eye: lint warnings are visible
@@ -31851,7 +31684,8 @@ function UnlimitedPointGraph(props) {
31851
31684
  const [[left, top]] = useTransformVectorsToPixels([minX, maxY]);
31852
31685
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("rect", {
31853
31686
  style: {
31854
- fill: "rgba(0,0,0,0)"
31687
+ fill: "rgba(0,0,0,0)",
31688
+ cursor: "crosshair"
31855
31689
  },
31856
31690
  width: widthPx,
31857
31691
  height: heightPx,
@@ -32035,6 +31869,22 @@ const MafsGraph = props => {
32035
31869
  const uniqueId = React.useId();
32036
31870
  const descriptionId = `interactive-graph-description-${uniqueId}`;
32037
31871
  const graphRef = React.useRef(null);
31872
+
31873
+ // Set up the SVG attributes for the nested SVGs that help lock
31874
+ // the grid and graph elements to the bounds of the graph.
31875
+ const {
31876
+ viewboxX,
31877
+ viewboxY
31878
+ } = calculateNestedSVGCoords(state.range, width, height);
31879
+ const viewBox = `${viewboxX} ${viewboxY} ${width} ${height}`;
31880
+ const nestedSVGAttributes = {
31881
+ width,
31882
+ height,
31883
+ viewBox,
31884
+ preserveAspectRatio: "xMidYMin",
31885
+ x: viewboxX,
31886
+ y: viewboxY
31887
+ };
32038
31888
  return /*#__PURE__*/React.createElement(GraphConfigContext.Provider, {
32039
31889
  value: {
32040
31890
  range: state.range,
@@ -32056,7 +31906,7 @@ const MafsGraph = props => {
32056
31906
  padding: "25px 25px 0 0",
32057
31907
  boxSizing: "content-box",
32058
31908
  marginLeft: "20px",
32059
- marginBottom: "20px",
31909
+ marginBottom: "30px",
32060
31910
  pointerEvents: props.static ? "none" : "auto",
32061
31911
  userSelect: "none",
32062
31912
  width,
@@ -32092,7 +31942,7 @@ const MafsGraph = props => {
32092
31942
  bottom: 0,
32093
31943
  left: 0
32094
31944
  }
32095
- }, props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels, null), /*#__PURE__*/React.createElement(AxisTickLabels, null)), /*#__PURE__*/React.createElement(Mafs, {
31945
+ }, props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisLabels, null)), /*#__PURE__*/React.createElement(Mafs, {
32096
31946
  preserveAspectRatio: false,
32097
31947
  viewBox: {
32098
31948
  x: state.range[X],
@@ -32103,37 +31953,59 @@ const MafsGraph = props => {
32103
31953
  zoom: false,
32104
31954
  width: width,
32105
31955
  height: height
32106
- }, /*#__PURE__*/React.createElement(SvgDefs, null), /*#__PURE__*/React.createElement(Grid, {
32107
- tickStep: props.step,
31956
+ }, /*#__PURE__*/React.createElement(SvgDefs, null), /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, /*#__PURE__*/React.createElement(Grid, {
32108
31957
  gridStep: props.gridStep,
32109
31958
  range: state.range,
32110
31959
  containerSizeClass: props.containerSizeClass,
32111
- markings: props.markings
32112
- }), props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
31960
+ markings: props.markings,
31961
+ width: width,
31962
+ height: height
31963
+ })),
31964
+ // Only render the axis ticks and arrows if the markings are set to a full "graph"
31965
+ props.markings === "graph" && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AxisTicks, null), /*#__PURE__*/React.createElement(AxisArrows, null)), /*#__PURE__*/React.createElement("svg", nestedSVGAttributes, props.lockedFigures && /*#__PURE__*/React.createElement(GraphLockedLayer, {
32113
31966
  lockedFigures: props.lockedFigures,
32114
31967
  range: state.range
32115
31968
  }), props.showProtractor && /*#__PURE__*/React.createElement(Protractor, null), renderGraph({
32116
31969
  state,
32117
31970
  dispatch
32118
- })))), renderGraphControls({
31971
+ }))))), renderGraphControls({
32119
31972
  state,
32120
- dispatch
31973
+ dispatch,
31974
+ width
32121
31975
  })));
32122
31976
  };
32123
- const renderPointGraphControls = props => /*#__PURE__*/React.createElement(Button, {
31977
+ const renderPointGraphControls = props => /*#__PURE__*/React.createElement(View, {
31978
+ style: {
31979
+ flexDirection: "row",
31980
+ width: props.width
31981
+ }
31982
+ }, /*#__PURE__*/React.createElement(Button, {
32124
31983
  kind: "secondary",
32125
31984
  style: {
32126
31985
  width: "100%",
32127
31986
  marginLeft: "20px"
32128
31987
  },
31988
+ tabIndex: 0,
32129
31989
  onClick: () => {
32130
31990
  props.dispatch(actions.pointGraph.addPoint([0, 0]));
32131
31991
  }
32132
- }, "Add Point");
31992
+ }, "Add Point"), (props.state.focusedPointIndex !== null || props.state.previouslyFocusedPointIndex !== null) && /*#__PURE__*/React.createElement(Button, {
31993
+ kind: "secondary",
31994
+ color: "destructive",
31995
+ tabIndex: 0,
31996
+ style: {
31997
+ width: "100%",
31998
+ marginLeft: "20px"
31999
+ },
32000
+ onClick: event => {
32001
+ props.dispatch(actions.pointGraph.removePoint(props.state.previouslyFocusedPointIndex));
32002
+ }
32003
+ }, "Remove Point"));
32133
32004
  const renderGraphControls = props => {
32134
32005
  const {
32135
32006
  state,
32136
- dispatch
32007
+ dispatch,
32008
+ width
32137
32009
  } = props;
32138
32010
  const {
32139
32011
  type
@@ -32143,7 +32015,8 @@ const renderGraphControls = props => {
32143
32015
  if (state.numPoints === "unlimited") {
32144
32016
  return renderPointGraphControls({
32145
32017
  state,
32146
- dispatch
32018
+ dispatch,
32019
+ width
32147
32020
  });
32148
32021
  }
32149
32022
  return null;
@@ -32151,6 +32024,56 @@ const renderGraphControls = props => {
32151
32024
  return null;
32152
32025
  }
32153
32026
  };
32027
+
32028
+ // Calculate the difference between the min and max values of a range
32029
+ const getRangeDiff = range => {
32030
+ const [min, max] = range;
32031
+ return Math.abs(max - min);
32032
+ };
32033
+
32034
+ // We need to adjust the nested SVG viewbox x and Y values based on the range of the graph in order
32035
+ // to ensure that the graph is sized and positioned correctly within the Mafs SVG and the clipping mask.
32036
+ // Exported for testing.
32037
+ const calculateNestedSVGCoords = (range, width, height) => {
32038
+ // X RANGE
32039
+ let viewboxX = 0; // When xMin is 0, we want to use 0 as the viewboxX value
32040
+ const totalXRange = getRangeDiff(range[X]);
32041
+ const gridCellWidth = width / totalXRange;
32042
+ const minX = range[X][MIN];
32043
+
32044
+ // If xMin is entirely positive, we need to adjust the
32045
+ // viewboxX to be the grid cell width multiplied by xMin
32046
+ if (minX > 0) {
32047
+ viewboxX = gridCellWidth * Math.abs(minX);
32048
+ }
32049
+ // If xMin is negative, we need to adjust the viewboxX to be
32050
+ // the negative value of the grid cell width multiplied by xMin
32051
+ if (minX < 0) {
32052
+ viewboxX = -gridCellWidth * Math.abs(minX);
32053
+ }
32054
+
32055
+ // Y RANGE
32056
+ let viewboxY = -height; // When yMin is 0, we want to use the negative value of the graph height
32057
+ const totalYRange = getRangeDiff(range[Y]);
32058
+ const gridCellHeight = height / totalYRange;
32059
+ const minY = range[Y][MIN];
32060
+
32061
+ // If the y range is entirely positive, we want a negative sum of the
32062
+ // height and the gridcell height multiplied by the absolute value of yMin
32063
+ if (minY > 0) {
32064
+ viewboxY = -height - gridCellHeight * Math.abs(minY);
32065
+ }
32066
+
32067
+ // If the yMin is negative, we want to multiply the gridcell height
32068
+ // by the absolute value of yMin, and subtract the full height of the graph
32069
+ if (minY < 0) {
32070
+ viewboxY = gridCellHeight * Math.abs(minY) - height;
32071
+ }
32072
+ return {
32073
+ viewboxX,
32074
+ viewboxY
32075
+ };
32076
+ };
32154
32077
  const renderGraph = props => {
32155
32078
  const {
32156
32079
  state,
@@ -32262,7 +32185,8 @@ function initializeGraphState(params) {
32262
32185
  type: graph.type,
32263
32186
  coords: getPointCoords(graph, range, step),
32264
32187
  numPoints: graph.numPoints || 0,
32265
- focusedPointIndex: null
32188
+ focusedPointIndex: null,
32189
+ previouslyFocusedPointIndex: null
32266
32190
  });
32267
32191
  case "circle":
32268
32192
  return _extends({}, shared, {
@@ -32555,6 +32479,7 @@ function doBlurPoint(state, action) {
32555
32479
  switch (state.type) {
32556
32480
  case "point":
32557
32481
  return _extends({}, state, {
32482
+ previouslyFocusedPointIndex: state.focusedPointIndex,
32558
32483
  focusedPointIndex: null
32559
32484
  });
32560
32485
  default:
@@ -32599,7 +32524,6 @@ function doMovePointInFigure(state, action) {
32599
32524
  }
32600
32525
  case "angle":
32601
32526
  case "circle":
32602
- throw new Error("FIXME implement circle reducer");
32603
32527
  case "point":
32604
32528
  case "polygon":
32605
32529
  case "quadratic":
@@ -32910,7 +32834,8 @@ function doRemovePoint(state, action) {
32910
32834
  }
32911
32835
  return _extends({}, state, {
32912
32836
  coords: state.coords.filter((_, i) => i !== action.index),
32913
- focusedPointIndex: null
32837
+ focusedPointIndex: null,
32838
+ previouslyFocusedPointIndex: null
32914
32839
  });
32915
32840
  }
32916
32841
  const getDeltaVertex = (maxMoves, minMoves, delta) => {
@@ -39737,15 +39662,15 @@ const TickMarks = Graphie.createSimpleClass((graphie, props) => {
39737
39662
 
39738
39663
  // Render the text labels
39739
39664
  results.push(graphie.style(props.isMobile ? {
39740
- color: KhanColors.BLUE_D
39665
+ color: KhanColors.BLUE
39741
39666
  } : {}, () => _label(graphie, props.labelStyle, leftLabel, leftLabel, base)));
39742
39667
  results.push(graphie.style(props.isMobile ? {
39743
- color: KhanColors.BLUE_D
39668
+ color: KhanColors.BLUE
39744
39669
  } : {}, () => _label(graphie, props.labelStyle, rightLabel, rightLabel, base)));
39745
39670
 
39746
39671
  // Render the labels' lines
39747
39672
  graphie.style({
39748
- stroke: props.isMobile ? KhanColors.BLUE_D : KhanColors.DYNAMIC,
39673
+ stroke: KhanColors.BLUE,
39749
39674
  strokeWidth: 3.5
39750
39675
  }, () => {
39751
39676
  results.push(graphie.line([leftLabel, -0.2], [leftLabel, 0.2]));
@@ -39912,21 +39837,21 @@ class NumberLine extends React.Component {
39912
39837
  if (isOpen) {
39913
39838
  fill = KhanColors._BACKGROUND;
39914
39839
  } else if (props.static) {
39915
- fill = KhanColors.DYNAMIC;
39840
+ fill = KhanColors.BLUE;
39916
39841
  } else {
39917
- fill = KhanColors.INTERACTIVE;
39842
+ fill = KhanColors.GREEN;
39918
39843
  }
39919
39844
  const normalStyle = {
39920
39845
  fill: fill,
39921
- stroke: props.static ? KhanColors.DYNAMIC : KhanColors.INTERACTIVE,
39846
+ stroke: props.static ? KhanColors.BLUE : KhanColors.GREEN,
39922
39847
  "stroke-width": isOpen ? 3 : 1
39923
39848
  };
39924
39849
  const highlightStyle = {
39925
- fill: isOpen ? KhanColors._BACKGROUND : KhanColors.INTERACTING,
39850
+ fill: isOpen ? KhanColors._BACKGROUND : KhanColors.GREEN,
39926
39851
  "stroke-width": isOpen ? 3 : 1
39927
39852
  };
39928
39853
  const mobileDotStyle = props.isInequality ? {
39929
- stroke: KhanColors.INTERACTIVE,
39854
+ stroke: KhanColors.GREEN,
39930
39855
  "fill-opacity": isOpen ? 0 : 1
39931
39856
  } : {};
39932
39857
  return /*#__PURE__*/React.createElement(MovablePoint
@@ -39984,7 +39909,7 @@ class NumberLine extends React.Component {
39984
39909
  const end = this._getInequalityEndpoint(props);
39985
39910
  const style = {
39986
39911
  arrows: "->",
39987
- stroke: this.props.apiOptions.isMobile ? KhanColors.INTERACTIVE : KhanColors.DYNAMIC,
39912
+ stroke: this.props.apiOptions.isMobile ? KhanColors.GREEN : KhanColors.BLUE,
39988
39913
  strokeWidth: 3.5
39989
39914
  };
39990
39915
  const isGreater = ["ge", "gt"].includes(props.rel);
@@ -44741,7 +44666,7 @@ const init = function init(options) {
44741
44666
 
44742
44667
  // This file is processed by a Rollup plugin (replace) to inject the production
44743
44668
  const libName = "@khanacademy/perseus";
44744
- const libVersion = "33.0.0";
44669
+ const libVersion = "33.2.0";
44745
44670
  addLibraryVersionToPerseusDebug(libName, libVersion);
44746
44671
 
44747
44672
  const apiVersion = {