@khanacademy/perseus 32.0.1 → 33.1.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/index.js CHANGED
@@ -10147,11 +10147,35 @@ const setLabelMargins = function (span, size) {
10147
10147
  marginTop: -height / 2 - y * scale
10148
10148
  });
10149
10149
  } else {
10150
+ const $container = $span.closest(".svg-image");
10151
+ // Ensuring that the line-height of the text doesn't throw off placement of the text element.
10152
+ // Inherited line-height values can really mess up placement.
10153
+ $container.css("line-height", "normal");
10154
+
10155
+ // The 'max-width' value is the same as the expected (100% scale) width of the graphie.
10156
+ // We are using jQuery to get this information since we don't have a way to pass it to this function.
10157
+ const expectedWidth = $container.css("max-width") ?? "0px";
10158
+ // We can calculate the true scale of the graphie by taking actual width and dividing by the expected width.
10159
+ // NOTE: Using 'slice' to remove the "px" unit from the end of the expected width value.
10160
+ const scale = ($container.width() ?? 0) / parseInt(expectedWidth.replace(/px$/, "")) * 100;
10161
+
10162
+ // Any padding needs to be scaled accordingly.
10163
+ const currentPadding = $span.css("padding") ?? "0px";
10164
+ const newPadding = Math.round(parseInt(currentPadding.slice(0, -2)) * scale) / 100;
10165
+
10166
+ // "multipliers" basically move the position of the text by using 1, 0, -1
10167
+ // 'margin-left' and 'margin-top' are used to position the text.
10168
+ // Margin and font size need to be scaled accordingly.
10150
10169
  const multipliers = labelDirections[direction || "center"];
10151
- $span.css({
10152
- marginLeft: Math.round(width * multipliers[0]),
10153
- marginTop: Math.round(height * multipliers[1])
10154
- });
10170
+ const styling = {
10171
+ marginLeft: Math.round(width * multipliers[0] * scale) / 100,
10172
+ marginTop: Math.round(height * multipliers[1] * scale) / 100,
10173
+ padding: `${newPadding}px`
10174
+ };
10175
+ if (scale !== 1) {
10176
+ styling["fontSize"] = `${Math.round(scale * 100) / 100}%`;
10177
+ }
10178
+ $span.css(styling);
10155
10179
  }
10156
10180
  };
10157
10181
  const GraphUtils = {
@@ -17536,9 +17560,16 @@ class SvgImage extends React__namespace.Component {
17536
17560
  // without coordinates. They don't seem to have any content, so
17537
17561
  // it seems fine to just ignore them (rather than error), but
17538
17562
  // we should figure out why this is happening.
17539
- const label = graphie.label(labelData.coordinates, labelData.content, labelData.alignment, labelData.typesetAsMath, {
17563
+
17564
+ // 'styling' - When a default scale (1) is used,
17565
+ // setting the font size to 100% is redundant.
17566
+ // Also, setting the font size to 100% can counteract other scale-based styling.
17567
+ // Therefore, when the scale is not applicable,
17568
+ // we set the value to 'null' so that no additional styling will be set.
17569
+ const styling = this.props.scale !== 1 ? {
17540
17570
  "font-size": 100 * this.props.scale + "%"
17541
- });
17571
+ } : null;
17572
+ const label = graphie.label(labelData.coordinates, labelData.content, labelData.alignment, labelData.typesetAsMath, styling);
17542
17573
 
17543
17574
  // Convert absolute positioning css from pixels to percentages
17544
17575
  // TODO(alex): Dynamically resize font-size as well. This
@@ -28586,6 +28617,95 @@ class Graph extends React__namespace.Component {
28586
28617
  }
28587
28618
  }
28588
28619
 
28620
+ function pathBuilder() {
28621
+ return new PathBuilder();
28622
+ }
28623
+ class PathBuilder {
28624
+ path = [];
28625
+ scaleFactor = 1;
28626
+ build() {
28627
+ return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
28628
+ }
28629
+
28630
+ // add a move (M) command to the path
28631
+ move(x, y) {
28632
+ this.path.push({
28633
+ action: "M",
28634
+ args: [x, y]
28635
+ });
28636
+ return this;
28637
+ }
28638
+ line(x, y) {
28639
+ this.path.push({
28640
+ action: "L",
28641
+ args: [x, y]
28642
+ });
28643
+ return this;
28644
+ }
28645
+ circularArc(radius, toX, toY) {
28646
+ let {
28647
+ sweep = false,
28648
+ largeArc = false
28649
+ } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
28650
+ this.path.push({
28651
+ action: "A",
28652
+ args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
28653
+ });
28654
+ return this;
28655
+ }
28656
+
28657
+ // add a curve (C) command to the path
28658
+ curve(control1X, control1Y, control2X, control2Y, endX, endY) {
28659
+ this.path.push({
28660
+ action: "C",
28661
+ args: [control1X, control1Y, control2X, control2Y, endX, endY]
28662
+ });
28663
+ return this;
28664
+ }
28665
+
28666
+ // Scale all coordinates of the path by a factor
28667
+ scale(factor) {
28668
+ this.scaleFactor *= factor;
28669
+ return this;
28670
+ }
28671
+ }
28672
+ function commandToString(command) {
28673
+ return `${command.action}${command.args.join(" ")}`;
28674
+ }
28675
+ function scaleCommandBy(scaleFactor) {
28676
+ return command => {
28677
+ switch (command.action) {
28678
+ case "A":
28679
+ // TODO(benchristel): do we want to refactor this switch to
28680
+ // use polymorphism?
28681
+ // Arc command
28682
+ return {
28683
+ ...command,
28684
+ args: [command.args[0] * scaleFactor,
28685
+ // x radius
28686
+ command.args[1] * scaleFactor,
28687
+ // y radius
28688
+ command.args[2],
28689
+ // rotation
28690
+ command.args[3],
28691
+ // largeArc flag
28692
+ command.args[4],
28693
+ // sweep flag
28694
+ command.args[5] * scaleFactor,
28695
+ // end x
28696
+ command.args[6] * scaleFactor // end y
28697
+ ]
28698
+ };
28699
+
28700
+ default:
28701
+ return {
28702
+ ...command,
28703
+ args: command.args.map(c => c * scaleFactor)
28704
+ };
28705
+ }
28706
+ };
28707
+ }
28708
+
28589
28709
  // Restricts `value` to be between `min` and `max`.
28590
28710
  function clamp(value, min, max) {
28591
28711
  if (value < min) {
@@ -28815,380 +28935,6 @@ function pixelsToVectors(pixels, graphState) {
28815
28935
  });
28816
28936
  }
28817
28937
 
28818
- function AxisLabels() {
28819
- const {
28820
- range,
28821
- labels,
28822
- width,
28823
- height
28824
- } = useGraphConfig();
28825
- const yAxisLabelLocation = [0, range[Y][MAX]];
28826
- const xAxisLabelLocation = [range[X][MAX], 0];
28827
- const [xAxisLabelText, yAxisLabelText] = labels;
28828
- const graphInfo = {
28829
- range,
28830
- width,
28831
- height
28832
- };
28833
- const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
28834
- // The default location for the y-axis-label is at the maximum y point
28835
- // This is just underneath the tick line for that point. The -24 moves the
28836
- // label up one grid square, so it sits on top of the graph
28837
- const [x2, y2] = mafs.vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
28838
- const {
28839
- TeX
28840
- } = getDependencies();
28841
- return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("span", {
28842
- style: {
28843
- position: "absolute",
28844
- left: x1,
28845
- top: y1,
28846
- fontSize: "14px",
28847
- transform: "translate(7px, -50%)"
28848
- }
28849
- }, /*#__PURE__*/React__default["default"].createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default["default"].createElement("span", {
28850
- style: {
28851
- position: "absolute",
28852
- left: x2,
28853
- top: y2,
28854
- fontSize: "14px",
28855
- transform: "translate(-50%, 0px)"
28856
- }
28857
- }, /*#__PURE__*/React__default["default"].createElement(TeX, null, yAxisLabelText)));
28858
- }
28859
-
28860
- // Universal padding for the axis ticks to ensure that the labels
28861
- // have enough space to render without overlapping the tick lines
28862
- const tickPadding = 5;
28863
- const AxisTickLabels = () => {
28864
- const graphConfig = useGraphConfig();
28865
- const {
28866
- tickStep,
28867
- range
28868
- } = graphConfig;
28869
- const [[xMin, xMax], [yMin, yMax]] = range;
28870
- const [xTickStep, yTickStep] = tickStep;
28871
- const yGridTicks = generateTickLocations$1(yTickStep, yMin, yMax);
28872
- const xGridTicks = generateTickLocations$1(xTickStep, xMin, xMax);
28873
- return /*#__PURE__*/React__namespace.createElement("div", {
28874
- className: "axis-tick-labels"
28875
- }, /*#__PURE__*/React__namespace.createElement(YGridAxis, {
28876
- axisTicks: yGridTicks,
28877
- graphConfig: graphConfig
28878
- }), /*#__PURE__*/React__namespace.createElement(XGridAxis, {
28879
- axisTicks: xGridTicks,
28880
- graphConfig: graphConfig
28881
- }));
28882
- };
28883
-
28884
- // Generate the necessary styles and ticks for the y-axis tick labels container
28885
- const YGridAxis = props => {
28886
- const {
28887
- axisTicks,
28888
- graphConfig
28889
- } = props;
28890
- const {
28891
- width,
28892
- height
28893
- } = graphConfig;
28894
-
28895
- // First get the label height by calculating the difference between the first two y-axis labels
28896
- const yTopPoint = pointToPixel([0, axisTicks[0]], graphConfig);
28897
- const ySecondPoint = pointToPixel([0, axisTicks[1]], graphConfig);
28898
- const yLabelHeight = ySecondPoint[1] - yTopPoint[1];
28899
-
28900
- // When rendering purely positive y-axis labels, we want to adjust the left position
28901
- // from the lowest calculated tick, as yMin may be negative
28902
- const yLowestTick = axisTicks[axisTicks.length - 1];
28903
- const yLeftAdjustment = Math.min(Math.max(yTopPoint[0] - tickPadding, 0), width);
28904
-
28905
- // We only want to render the 0 label on the y-axis if it is left of the grid
28906
- const yAxisIsLeftOfGrid = yLeftAdjustment === 0;
28907
-
28908
- // If the y-axis is right of the graph's viewbox/range,
28909
- // we want to adjust both the positioning and text alignment
28910
- const yAxisRightOfGrid = yLeftAdjustment === width;
28911
-
28912
- // Determine the default spacing for the labels based on whether the y-axis is right of the grid
28913
- const defaultSpacing = yAxisRightOfGrid ? 0.5 : 0;
28914
-
28915
- // We also want to adjust the spacing if there are no negative y-axis labels as the extra space is not needed
28916
- const marginSpacing = yLowestTick >= 0 ? defaultSpacing * 2 : defaultSpacing;
28917
-
28918
- // Determine the text alignment based on whether the y-axis is right of the grid
28919
- // We need to cast this as a const as it is used in the inline styles
28920
- const textAlign = yAxisRightOfGrid ? "left" : "right";
28921
- const yAxisStyles = {
28922
- left: `calc(${yLeftAdjustment}px - ${marginSpacing}em)`,
28923
- top: `calc(${yTopPoint[1]}px - 0.5em)`,
28924
- height,
28925
- textAlign,
28926
- "--y-axis-label-height": yLabelHeight + "px"
28927
- };
28928
- const classNames = yAxisRightOfGrid ? "y-axis-tick-labels y-axis-right-of-grid" : "y-axis-tick-labels ";
28929
- return /*#__PURE__*/React__namespace.createElement("div", {
28930
- className: classNames,
28931
- "data-testid": "y-axis-tick-labels",
28932
- style: yAxisStyles
28933
- }, axisTicks.map(label => {
28934
- return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
28935
- label: label,
28936
- axis: "y",
28937
- key: `y-grid-tick-${label}`,
28938
- graphConfig: graphConfig,
28939
- axisOutOfBounds: yAxisIsLeftOfGrid
28940
- });
28941
- }));
28942
- };
28943
-
28944
- // Generate the necessary styles and ticks for the x-axis tick labels container
28945
- const XGridAxis = props => {
28946
- const {
28947
- axisTicks,
28948
- graphConfig
28949
- } = props;
28950
- const {
28951
- width,
28952
- height
28953
- } = graphConfig;
28954
-
28955
- // Determine label width by calculating the difference between the first two x-axis labels
28956
- const xFirstPoint = pointToPixel([axisTicks[0], 0], graphConfig);
28957
- const xSecondPoint = pointToPixel([axisTicks[1], 0], graphConfig);
28958
- const xLabelWidth = Math.abs(xSecondPoint[0] - xFirstPoint[0]);
28959
-
28960
- // Determine the top position of the x-axis labels based on
28961
- // whether the x-axis is above, within, or below the graph
28962
- const xAxisAboveGraph = xFirstPoint[1] < 0;
28963
- const xTopAdjustment = xAxisAboveGraph ? 0 : Math.min(xFirstPoint[1] + tickPadding, height);
28964
-
28965
- // Determine whether the x-axis is outside of the graph's viewbox/range
28966
- // This is used to conditionally render the 0 label on the x-axis
28967
- const xAxisOutOfBounds = xTopAdjustment === height || xAxisAboveGraph;
28968
-
28969
- // Determine the available space to the right of the x-axis labels
28970
- const availableSpaceRight = width - xFirstPoint[0];
28971
-
28972
- // Calculate the total combined width of ALL the x-axis labels
28973
- const axisTicksWidth = axisTicks.length * xLabelWidth;
28974
-
28975
- // Determine if we need to increase the width of the axis past the graph width
28976
- const calculatedWidth = axisTicksWidth > width ? axisTicksWidth : width;
28977
-
28978
- // Determine the right adjustment for the x-axis labels based on the available space
28979
- // We're adjusting the right as the flex-direction is row-reverse
28980
- const xRightAdjustment = availableSpaceRight - xLabelWidth / 2;
28981
- const xAxisStyles = {
28982
- top: xTopAdjustment,
28983
- right: xRightAdjustment,
28984
- width: calculatedWidth,
28985
- "--x-axis-label-width": xLabelWidth + "px"
28986
- };
28987
- return /*#__PURE__*/React__namespace.createElement("div", {
28988
- className: `x-axis-tick-labels ${xAxisAboveGraph && "x-axis-top-of-grid"}`,
28989
- "data-testid": "x-axis-tick-labels",
28990
- style: xAxisStyles
28991
- }, axisTicks.map(label => {
28992
- return /*#__PURE__*/React__namespace.createElement(AxisTickLabel, {
28993
- axis: "x",
28994
- label: label,
28995
- key: `x-grid-tick-${label}`,
28996
- graphConfig: graphConfig,
28997
- axisOutOfBounds: xAxisOutOfBounds
28998
- });
28999
- }));
29000
- };
29001
-
29002
- // Generate the individual tick label elements
29003
- const AxisTickLabel = _ref => {
29004
- let {
29005
- label,
29006
- graphConfig,
29007
- axisOutOfBounds,
29008
- axis
29009
- } = _ref;
29010
- const {
29011
- gridStep,
29012
- tickStep
29013
- } = graphConfig;
29014
- // Determine the point on the axis based on the axis type
29015
- const pointOnAxis = axis === "x" ? [label, 0] : [0, label];
29016
- const pixelPoint = pointToPixel(pointOnAxis, graphConfig);
29017
-
29018
- // Determine the relevant edge of the graph based on the axis type
29019
- const graphEdge = axis === "x" ? graphConfig.width : graphConfig.height;
29020
-
29021
- // Determine the vector index based on the axis type
29022
- const vectorIndex = axis === "x" ? 0 : 1;
29023
-
29024
- // Determine whether or not to render the tick label text
29025
- const shouldShowLabel = showTickLabel({
29026
- label,
29027
- axisOutOfBounds,
29028
- graphEdge,
29029
- position: pixelPoint[vectorIndex],
29030
- gridStep: gridStep[vectorIndex],
29031
- tickStep: tickStep[vectorIndex]
29032
- });
29033
- return /*#__PURE__*/React__namespace.createElement("span", {
29034
- className: `${axis}-axis-tick-label`
29035
- }, shouldShowLabel && label);
29036
- };
29037
-
29038
- // Determine whether or not to show the tick label text
29039
- const showTickLabel = _ref2 => {
29040
- let {
29041
- gridStep,
29042
- tickStep,
29043
- label,
29044
- graphEdge,
29045
- position,
29046
- axisOutOfBounds
29047
- } = _ref2;
29048
- let showLabel = true;
29049
-
29050
- // We only want to show the initial negative tick labels (e.g. -1) on each
29051
- // axis if the tickStep > gridStep, to ensure that these labels do not overlap.
29052
- // e.g. If gridStep = 1 and tickStep = 2, there are 2 grid lines for every 1 tick,
29053
- // which allows enough room for both these tick labels to render.
29054
- showLabel = tickStep > gridStep ? true : label !== -tickStep;
29055
-
29056
- // If the tick label position is greater than the relevant edge of the graph, don't render it
29057
- if (position <= -graphEdge || position >= graphEdge) {
29058
- showLabel = false;
29059
- }
29060
-
29061
- // If the label is 0, we only want to show it if the axis is to the left of the graph's viewbox/range
29062
- // otherwise it will overlap with graph axis labels
29063
- if (label === 0 && !axisOutOfBounds) {
29064
- showLabel = false;
29065
- }
29066
- return showLabel;
29067
- };
29068
-
29069
- // Generate the tick labels for an axis based on the tick step
29070
- function generateTickLocations$1(tickStep, min, max) {
29071
- const positiveTicks = [];
29072
- const negativeTicks = [];
29073
- const ticks = [];
29074
-
29075
- // Add 0 if it is applicable.
29076
- // This will be conditionally rendered using showTickLabel.
29077
- if (min <= 0 && max >= 0) {
29078
- positiveTicks.push(0);
29079
- }
29080
-
29081
- // Add ticks on the positive axis
29082
- // Start at the first tick after 0 or the minimum value,
29083
- // taking into account that the graph may be zoomed in on the positive axis
29084
- let i = Math.max(min, 0) + tickStep;
29085
- for (i; min < i && i < max; i += tickStep) {
29086
- positiveTicks.push(i);
29087
- }
29088
-
29089
- // Add ticks on the negative axis
29090
- // Start at the first tick before 0 or the maximum value,
29091
- // taking into account that the graph may be zoomed in on the negative axis
29092
- i = Math.min(max, 0) - tickStep;
29093
- for (i; i > min; i -= tickStep) {
29094
- negativeTicks.push(i);
29095
- }
29096
-
29097
- // Reverse the ticks so that they are in the correct render order
29098
- positiveTicks.reverse();
29099
- ticks.push(...positiveTicks, ...negativeTicks);
29100
- return ticks;
29101
- }
29102
-
29103
- function pathBuilder() {
29104
- return new PathBuilder();
29105
- }
29106
- class PathBuilder {
29107
- path = [];
29108
- scaleFactor = 1;
29109
- build() {
29110
- return this.path.map(scaleCommandBy(this.scaleFactor)).map(commandToString).join("");
29111
- }
29112
-
29113
- // add a move (M) command to the path
29114
- move(x, y) {
29115
- this.path.push({
29116
- action: "M",
29117
- args: [x, y]
29118
- });
29119
- return this;
29120
- }
29121
- line(x, y) {
29122
- this.path.push({
29123
- action: "L",
29124
- args: [x, y]
29125
- });
29126
- return this;
29127
- }
29128
- circularArc(radius, toX, toY) {
29129
- let {
29130
- sweep = false,
29131
- largeArc = false
29132
- } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
29133
- this.path.push({
29134
- action: "A",
29135
- args: [radius, radius, 0 /* rotation */, largeArc ? 1 : 0, sweep ? 1 : 0, toX, toY]
29136
- });
29137
- return this;
29138
- }
29139
-
29140
- // add a curve (C) command to the path
29141
- curve(control1X, control1Y, control2X, control2Y, endX, endY) {
29142
- this.path.push({
29143
- action: "C",
29144
- args: [control1X, control1Y, control2X, control2Y, endX, endY]
29145
- });
29146
- return this;
29147
- }
29148
-
29149
- // Scale all coordinates of the path by a factor
29150
- scale(factor) {
29151
- this.scaleFactor *= factor;
29152
- return this;
29153
- }
29154
- }
29155
- function commandToString(command) {
29156
- return `${command.action}${command.args.join(" ")}`;
29157
- }
29158
- function scaleCommandBy(scaleFactor) {
29159
- return command => {
29160
- switch (command.action) {
29161
- case "A":
29162
- // TODO(benchristel): do we want to refactor this switch to
29163
- // use polymorphism?
29164
- // Arc command
29165
- return {
29166
- ...command,
29167
- args: [command.args[0] * scaleFactor,
29168
- // x radius
29169
- command.args[1] * scaleFactor,
29170
- // y radius
29171
- command.args[2],
29172
- // rotation
29173
- command.args[3],
29174
- // largeArc flag
29175
- command.args[4],
29176
- // sweep flag
29177
- command.args[5] * scaleFactor,
29178
- // end x
29179
- command.args[6] * scaleFactor // end y
29180
- ]
29181
- };
29182
-
29183
- default:
29184
- return {
29185
- ...command,
29186
- args: command.args.map(c => c * scaleFactor)
29187
- };
29188
- }
29189
- };
29190
- }
29191
-
29192
28938
  // We use the pathBuilder here to scale up the SVG path coordinates used
29193
28939
  // elsewhere for arrowheads. We scale in the path itself instead of using a CSS
29194
28940
  // transform because a transform would also scale up the stroke weight, and we
@@ -29218,7 +28964,10 @@ function AxisArrows() {
29218
28964
  range: [[xMin, xMax], [yMin, yMax]]
29219
28965
  } = useGraphConfig();
29220
28966
  const axisColor = "var(--mafs-fg)";
29221
- return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
28967
+
28968
+ // Only render the arrows if the axis is within the visible range
28969
+ // as otherwise the arrows will be rendered outside the graph
28970
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, !(yMin > 0 || yMax < 0) && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29222
28971
  color: axisColor,
29223
28972
  tip: [xMin, 0],
29224
28973
  angle: 180
@@ -29226,7 +28975,7 @@ function AxisArrows() {
29226
28975
  color: axisColor,
29227
28976
  tip: [xMax, 0],
29228
28977
  angle: 0
29229
- }), /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
28978
+ })), !(xMin > 0 || xMax < 0) && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(Arrowhead, {
29230
28979
  color: axisColor,
29231
28980
  tip: [0, yMin],
29232
28981
  angle: 90
@@ -29234,39 +28983,76 @@ function AxisArrows() {
29234
28983
  color: axisColor,
29235
28984
  tip: [0, yMax],
29236
28985
  angle: 270
29237
- }));
28986
+ })));
29238
28987
  }
29239
28988
 
28989
+ function AxisLabels() {
28990
+ const {
28991
+ range,
28992
+ labels,
28993
+ width,
28994
+ height
28995
+ } = useGraphConfig();
28996
+ const yAxisLabelLocation = [0, range[Y][MAX]];
28997
+ const xAxisLabelLocation = [range[X][MAX], 0];
28998
+ const [xAxisLabelText, yAxisLabelText] = labels;
28999
+ const graphInfo = {
29000
+ range,
29001
+ width,
29002
+ height
29003
+ };
29004
+ const [x1, y1] = pointToPixel(xAxisLabelLocation, graphInfo);
29005
+ // The default location for the y-axis-label is at the maximum y point
29006
+ // This is just underneath the tick line for that point. The -24 moves the
29007
+ // label up one grid square, so it sits on top of the graph
29008
+ const [x2, y2] = mafs.vec.add(pointToPixel(yAxisLabelLocation, graphInfo), [0, -24]);
29009
+ const {
29010
+ TeX
29011
+ } = getDependencies();
29012
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement("span", {
29013
+ style: {
29014
+ position: "absolute",
29015
+ left: x1,
29016
+ top: y1,
29017
+ fontSize: "14px",
29018
+ transform: "translate(7px, -50%)"
29019
+ }
29020
+ }, /*#__PURE__*/React__default["default"].createElement(TeX, null, xAxisLabelText)), /*#__PURE__*/React__default["default"].createElement("span", {
29021
+ style: {
29022
+ position: "absolute",
29023
+ left: x2,
29024
+ top: y2,
29025
+ fontSize: "14px",
29026
+ transform: "translate(-50%, 0px)"
29027
+ }
29028
+ }, /*#__PURE__*/React__default["default"].createElement(TeX, null, yAxisLabelText)));
29029
+ }
29030
+
29031
+ // The size of the ticks and labels in pixels
29240
29032
  const tickSize = 10;
29241
- const tickStyle = {
29242
- stroke: "black",
29243
- strokeWidth: 1
29244
- };
29033
+ const tickLabelSize = 14;
29245
29034
  const YGridTick = _ref => {
29246
29035
  let {
29247
29036
  y,
29248
- graphInfo
29037
+ range
29249
29038
  } = _ref;
29039
+ // If the graph requires out-of-bounds labels, we want to make sure to set the
29040
+ // coordinates to the edge of the visible range of the graph. Otherwise,
29041
+ // the ticks and labels would render outside of the clipping-mask.
29250
29042
  let xPointOnAxis = 0;
29251
-
29252
- // If the graph is zoomed in, we want to make sure the ticks are still visible
29253
- // even if they are outside the graph's range.
29254
- if (graphInfo.range[X][MIN] > 0) {
29043
+ if (range[X][MIN] > 0) {
29255
29044
  // If the graph is on the positive side of the x-axis, lock the ticks to the left side of the graph
29256
- xPointOnAxis = graphInfo.range[X][MIN];
29045
+ xPointOnAxis = range[X][MIN];
29257
29046
  }
29258
- if (graphInfo.range[X][MAX] < 0) {
29047
+ if (range[X][MAX] < 0) {
29259
29048
  // If the graph is on the negative side of the x-axis, lock the ticks to the right side of the graph
29260
- xPointOnAxis = graphInfo.range[X][MAX];
29049
+ xPointOnAxis = range[X][MAX];
29261
29050
  }
29051
+
29052
+ // Convert the Vector2 coordinates to pixel coordinates
29262
29053
  const pointOnAxis = [xPointOnAxis, y];
29263
29054
  const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
29264
29055
 
29265
- // If the tick is on the edge of the graph's range, don't render it
29266
- if (yPosition === -graphInfo.height || yPosition === graphInfo.height + 20) {
29267
- return null;
29268
- }
29269
-
29270
29056
  // Position of the start of the tick
29271
29057
  const x1 = xPosition - tickSize / 2;
29272
29058
  const y1 = yPosition;
@@ -29274,40 +29060,56 @@ const YGridTick = _ref => {
29274
29060
  // Position of the end of the tick
29275
29061
  const x2 = xPosition + tickSize / 2;
29276
29062
  const y2 = yPosition;
29063
+
29064
+ // Adjust the y position of the x-axis labels based on
29065
+ // whether the x-axis is above, within, or below the graph
29066
+ const xAdjustment = range[X][MAX] <= 0 ? tickLabelSize * 1.5 : -tickLabelSize * 1.1;
29067
+ const xPositionText = xPosition + xAdjustment;
29068
+ const yPositionText = yPosition + tickLabelSize * 0.25; // Center the text vertically on the tick
29069
+
29070
+ // If the graph displays both the y and x axis lines within the graph, we want
29071
+ // to hide the label at -1 on the y-axis to prevent overlap with the x-axis label
29072
+ const showLabel = shouldShowLabel(y, range);
29277
29073
  return /*#__PURE__*/React__namespace.createElement("g", {
29278
- className: "y-axis-ticks"
29074
+ className: "tick"
29279
29075
  }, /*#__PURE__*/React__namespace.createElement("line", {
29280
29076
  x1: x1,
29281
29077
  y1: y1,
29282
29078
  x2: x2,
29283
29079
  y2: y2,
29284
- style: tickStyle
29285
- }));
29080
+ className: "axis-tick"
29081
+ }), showLabel && /*#__PURE__*/React__namespace.createElement("text", {
29082
+ className: "axis-tick-label",
29083
+ style: {
29084
+ fontSize: tickLabelSize
29085
+ },
29086
+ textAnchor: "end",
29087
+ x: xPositionText,
29088
+ y: yPositionText
29089
+ }, y.toString()));
29286
29090
  };
29287
29091
  const XGridTick = _ref2 => {
29288
29092
  let {
29289
29093
  x,
29290
- graphInfo
29094
+ range
29291
29095
  } = _ref2;
29096
+ // If the graph requires out-of-bounds labels, we want to make sure to set the
29097
+ // coordinates to the edge of the visible range of the graph. Otherwise,
29098
+ // the ticks and labels would render outside of the clipping-mask.
29292
29099
  let yPointOnAxis = 0;
29293
- // If the graph is zoomed in, we want to make sure the ticks are still visible
29294
- // even if they are outside the graph's range.
29295
- if (graphInfo.range[Y][MIN] > 0) {
29100
+ if (range[Y][MIN] > 0) {
29296
29101
  // If the graph is on the positive side of the y-axis, lock the ticks to the top of the graph
29297
- yPointOnAxis = graphInfo.range[Y][MIN];
29102
+ yPointOnAxis = range[Y][MIN];
29298
29103
  }
29299
- if (graphInfo.range[Y][MAX] < 0) {
29104
+ if (range[Y][MAX] < 0) {
29300
29105
  // If the graph is on the negative side of the x-axis, lock the ticks to the bottom of the graph
29301
- yPointOnAxis = graphInfo.range[Y][MAX];
29106
+ yPointOnAxis = range[Y][MAX];
29302
29107
  }
29108
+
29109
+ // Convert the Vector2 coordinates to pixel coordinates
29303
29110
  const pointOnAxis = [x, yPointOnAxis];
29304
29111
  const [[xPosition, yPosition]] = useTransformVectorsToPixels(pointOnAxis);
29305
29112
 
29306
- // If the tick is on the edge of the graph's range, don't render it
29307
- if (xPosition === -graphInfo.width / 2 || xPosition === graphInfo.width) {
29308
- return null;
29309
- }
29310
-
29311
29113
  // Position of the start of the tick
29312
29114
  const x1 = xPosition;
29313
29115
  const y1 = yPosition + tickSize / 2;
@@ -29315,21 +29117,56 @@ const XGridTick = _ref2 => {
29315
29117
  // Position of the end of the tick
29316
29118
  const x2 = xPosition;
29317
29119
  const y2 = yPosition - tickSize / 2;
29120
+
29121
+ // Adjust the Y position of the x-axis labels based on
29122
+ // whether the x-axis is above, within, or below the graph
29123
+ const yAdjustment = range[Y][MAX] < 0 ? -tickLabelSize : tickLabelSize * 1.75;
29124
+
29125
+ // Adjust the X position of the x-axis labels based on
29126
+ // whether the label is positive or negative, in order to
29127
+ // account for the width of the negative sign
29128
+ const xAdjustment = x < 0 ? -2 : 0;
29129
+
29130
+ // Apply the adjustments to the x and y positions for the text
29131
+ const xPositionText = xPosition + xAdjustment;
29132
+ const yPositionText = yPosition + yAdjustment;
29318
29133
  return /*#__PURE__*/React__namespace.createElement("g", {
29319
- className: "x-axis-ticks"
29134
+ className: "tick"
29320
29135
  }, /*#__PURE__*/React__namespace.createElement("line", {
29321
29136
  x1: x1,
29322
29137
  y1: y1,
29323
29138
  x2: x2,
29324
29139
  y2: y2,
29325
- style: tickStyle
29326
- }));
29140
+ className: "axis-tick"
29141
+ }), /*#__PURE__*/React__namespace.createElement("text", {
29142
+ className: "axis-tick-label",
29143
+ style: {
29144
+ fontSize: tickLabelSize
29145
+ },
29146
+ textAnchor: "middle",
29147
+ x: xPositionText,
29148
+ y: yPositionText
29149
+ }, x.toString()));
29150
+ };
29151
+
29152
+ // Determines whether to show the label for the given tick
29153
+ // Currently, the only condition is to hide the label at -1
29154
+ // on the y-axis when the x-axis is within the graph
29155
+ const shouldShowLabel = (number, range) => {
29156
+ let showLabel = true;
29157
+
29158
+ // If the x-axis is within the graph and the y-axis is at -1, hide the label
29159
+ if (range[X][MIN] < -1 && range[X][MAX] > 0 && number === -1) {
29160
+ showLabel = false;
29161
+ }
29162
+ return showLabel;
29327
29163
  };
29328
29164
  function generateTickLocations(tickStep, min, max) {
29329
29165
  const ticks = [];
29330
29166
 
29331
29167
  // Add ticks in the positive direction
29332
- for (let i = 0 + tickStep; i < max; i += tickStep) {
29168
+ const start = Math.max(min, 0);
29169
+ for (let i = start + tickStep; i < max; i += tickStep) {
29333
29170
  ticks.push(i);
29334
29171
  }
29335
29172
 
@@ -29344,34 +29181,34 @@ function generateTickLocations(tickStep, min, max) {
29344
29181
  const AxisTicks = () => {
29345
29182
  const {
29346
29183
  tickStep,
29347
- range,
29348
- width,
29349
- height
29184
+ range
29350
29185
  } = useGraphConfig();
29351
- const graphInfo = {
29352
- range,
29353
- width,
29354
- height
29355
- };
29356
29186
  const [[xMin, xMax], [yMin, yMax]] = range;
29357
29187
  const [xTickStep, yTickStep] = tickStep;
29188
+
29189
+ // Generate the tick locations & labels for the x and y axes
29358
29190
  const yGridTicks = generateTickLocations(yTickStep, yMin, yMax);
29359
29191
  const xGridTicks = generateTickLocations(xTickStep, xMin, xMax);
29360
29192
  return /*#__PURE__*/React__namespace.createElement("g", {
29361
- className: "axis-ticks"
29193
+ className: "axis-ticks",
29194
+ role: "presentation"
29195
+ }, /*#__PURE__*/React__namespace.createElement("g", {
29196
+ className: "y-axis-ticks"
29362
29197
  }, yGridTicks.map(y => {
29363
29198
  return /*#__PURE__*/React__namespace.createElement(YGridTick, {
29364
29199
  y: y,
29365
29200
  key: `y-grid-tick-${y}`,
29366
- graphInfo: graphInfo
29201
+ range: range
29367
29202
  });
29368
- }), xGridTicks.map(x => {
29203
+ })), /*#__PURE__*/React__namespace.createElement("g", {
29204
+ className: "x-axis-ticks"
29205
+ }, xGridTicks.map(x => {
29369
29206
  return /*#__PURE__*/React__namespace.createElement(XGridTick, {
29370
29207
  x: x,
29371
29208
  key: `x-grid-tick-${x}`,
29372
- graphInfo: graphInfo
29209
+ range: range
29373
29210
  });
29374
- }));
29211
+ })));
29375
29212
  };
29376
29213
 
29377
29214
  /**
@@ -29392,12 +29229,10 @@ const axisOptions = (props, axisIndex) => {
29392
29229
  };
29393
29230
  };
29394
29231
  const Grid = props => {
29395
- return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
29232
+ return props.markings === "none" ? null : /*#__PURE__*/React__namespace.createElement(mafs.Coordinates.Cartesian, {
29396
29233
  xAxis: axisOptions(props, X),
29397
29234
  yAxis: axisOptions(props, Y)
29398
- }),
29399
- // Only render the axis ticks and arrows if the markings are set to a full "graph"
29400
- props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)));
29235
+ });
29401
29236
  };
29402
29237
 
29403
29238
  // Displays a stylized open eye: lint warnings are visible
@@ -32330,11 +32165,31 @@ const MafsGraph = props => {
32330
32165
  state,
32331
32166
  dispatch,
32332
32167
  labels,
32333
- readOnly
32168
+ readOnly,
32169
+ fullGraphAriaLabel,
32170
+ fullGraphAriaDescription
32334
32171
  } = props;
32335
32172
  const [width, height] = props.box;
32336
32173
  const tickStep = props.step;
32174
+ const uniqueId = React__namespace.useId();
32175
+ const descriptionId = `interactive-graph-description-${uniqueId}`;
32337
32176
  const graphRef = React__namespace.useRef(null);
32177
+
32178
+ // Set up the SVG attributes for the nested SVGs that help lock
32179
+ // the grid and graph elements to the bounds of the graph.
32180
+ const {
32181
+ viewboxX,
32182
+ viewboxY
32183
+ } = calculateNestedSVGCoords(state.range, width, height);
32184
+ const viewBox = `${viewboxX} ${viewboxY} ${width} ${height}`;
32185
+ const nestedSVGAttributes = {
32186
+ width,
32187
+ height,
32188
+ viewBox,
32189
+ preserveAspectRatio: "xMidYMin",
32190
+ x: viewboxX,
32191
+ y: viewboxY
32192
+ };
32338
32193
  return /*#__PURE__*/React__namespace.createElement(GraphConfigContext.Provider, {
32339
32194
  value: {
32340
32195
  range: state.range,
@@ -32356,7 +32211,7 @@ const MafsGraph = props => {
32356
32211
  padding: "25px 25px 0 0",
32357
32212
  boxSizing: "content-box",
32358
32213
  marginLeft: "20px",
32359
- marginBottom: "20px",
32214
+ marginBottom: "30px",
32360
32215
  pointerEvents: props.static ? "none" : "auto",
32361
32216
  userSelect: "none",
32362
32217
  width,
@@ -32368,9 +32223,19 @@ const MafsGraph = props => {
32368
32223
  graphRef.current?.focus();
32369
32224
  }
32370
32225
  },
32226
+ "aria-label": fullGraphAriaLabel,
32227
+ "aria-describedby": fullGraphAriaDescription ? descriptionId : undefined,
32371
32228
  ref: graphRef,
32372
32229
  tabIndex: 0
32373
- }, /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32230
+ }, fullGraphAriaDescription && /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
32231
+ id: descriptionId,
32232
+ tabIndex: -1,
32233
+ style: {
32234
+ width: 0,
32235
+ height: 0,
32236
+ overflow: "hidden"
32237
+ }
32238
+ }, fullGraphAriaDescription), /*#__PURE__*/React__namespace.createElement(LegacyGrid, {
32374
32239
  box: props.box,
32375
32240
  backgroundImage: props.backgroundImage
32376
32241
  }), props.showLabelsFlag && props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLabelsLayer, {
@@ -32381,7 +32246,7 @@ const MafsGraph = props => {
32381
32246
  bottom: 0,
32382
32247
  left: 0
32383
32248
  }
32384
- }, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null), /*#__PURE__*/React__namespace.createElement(AxisTickLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
32249
+ }, props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisLabels, null)), /*#__PURE__*/React__namespace.createElement(mafs.Mafs, {
32385
32250
  preserveAspectRatio: false,
32386
32251
  viewBox: {
32387
32252
  x: state.range[X],
@@ -32392,19 +32257,22 @@ const MafsGraph = props => {
32392
32257
  zoom: false,
32393
32258
  width: width,
32394
32259
  height: height
32395
- }, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement(Grid, {
32396
- tickStep: props.step,
32260
+ }, /*#__PURE__*/React__namespace.createElement(SvgDefs, null), /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, /*#__PURE__*/React__namespace.createElement(Grid, {
32397
32261
  gridStep: props.gridStep,
32398
32262
  range: state.range,
32399
32263
  containerSizeClass: props.containerSizeClass,
32400
- markings: props.markings
32401
- }), props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
32264
+ markings: props.markings,
32265
+ width: width,
32266
+ height: height
32267
+ })),
32268
+ // Only render the axis ticks and arrows if the markings are set to a full "graph"
32269
+ props.markings === "graph" && /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(AxisTicks, null), /*#__PURE__*/React__namespace.createElement(AxisArrows, null)), /*#__PURE__*/React__namespace.createElement("svg", nestedSVGAttributes, props.lockedFigures && /*#__PURE__*/React__namespace.createElement(GraphLockedLayer, {
32402
32270
  lockedFigures: props.lockedFigures,
32403
32271
  range: state.range
32404
32272
  }), props.showProtractor && /*#__PURE__*/React__namespace.createElement(Protractor, null), renderGraph({
32405
32273
  state,
32406
32274
  dispatch
32407
- })))), renderGraphControls({
32275
+ }))))), renderGraphControls({
32408
32276
  state,
32409
32277
  dispatch
32410
32278
  })));
@@ -32440,6 +32308,56 @@ const renderGraphControls = props => {
32440
32308
  return null;
32441
32309
  }
32442
32310
  };
32311
+
32312
+ // Calculate the difference between the min and max values of a range
32313
+ const getRangeDiff = range => {
32314
+ const [min, max] = range;
32315
+ return Math.abs(max - min);
32316
+ };
32317
+
32318
+ // We need to adjust the nested SVG viewbox x and Y values based on the range of the graph in order
32319
+ // to ensure that the graph is sized and positioned correctly within the Mafs SVG and the clipping mask.
32320
+ // Exported for testing.
32321
+ const calculateNestedSVGCoords = (range, width, height) => {
32322
+ // X RANGE
32323
+ let viewboxX = 0; // When xMin is 0, we want to use 0 as the viewboxX value
32324
+ const totalXRange = getRangeDiff(range[X]);
32325
+ const gridCellWidth = width / totalXRange;
32326
+ const minX = range[X][MIN];
32327
+
32328
+ // If xMin is entirely positive, we need to adjust the
32329
+ // viewboxX to be the grid cell width multiplied by xMin
32330
+ if (minX > 0) {
32331
+ viewboxX = gridCellWidth * Math.abs(minX);
32332
+ }
32333
+ // If xMin is negative, we need to adjust the viewboxX to be
32334
+ // the negative value of the grid cell width multiplied by xMin
32335
+ if (minX < 0) {
32336
+ viewboxX = -gridCellWidth * Math.abs(minX);
32337
+ }
32338
+
32339
+ // Y RANGE
32340
+ let viewboxY = -height; // When yMin is 0, we want to use the negative value of the graph height
32341
+ const totalYRange = getRangeDiff(range[Y]);
32342
+ const gridCellHeight = height / totalYRange;
32343
+ const minY = range[Y][MIN];
32344
+
32345
+ // If the y range is entirely positive, we want a negative sum of the
32346
+ // height and the gridcell height multiplied by the absolute value of yMin
32347
+ if (minY > 0) {
32348
+ viewboxY = -height - gridCellHeight * Math.abs(minY);
32349
+ }
32350
+
32351
+ // If the yMin is negative, we want to multiply the gridcell height
32352
+ // by the absolute value of yMin, and subtract the full height of the graph
32353
+ if (minY < 0) {
32354
+ viewboxY = gridCellHeight * Math.abs(minY) - height;
32355
+ }
32356
+ return {
32357
+ viewboxX,
32358
+ viewboxY
32359
+ };
32360
+ };
32443
32361
  const renderGraph = props => {
32444
32362
  const {
32445
32363
  state,
@@ -45054,7 +44972,7 @@ const init = function (options) {
45054
44972
 
45055
44973
  // This file is processed by a Rollup plugin (replace) to inject the production
45056
44974
  const libName = "@khanacademy/perseus";
45057
- const libVersion = "32.0.1";
44975
+ const libVersion = "33.1.0";
45058
44976
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45059
44977
 
45060
44978
  const apiVersion = {
@@ -45948,128 +45866,6 @@ const ref = /*#__PURE__*/React__namespace.forwardRef((props, ref) => /*#__PURE__
45948
45866
  }));
45949
45867
  }));
45950
45868
 
45951
- class ArrowPicker extends React__namespace.Component {
45952
- static defaultProps = {
45953
- value: ""
45954
- };
45955
- render() {
45956
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
45957
- value: this.props.value,
45958
- allowEmpty: false,
45959
- buttons: [{
45960
- value: "",
45961
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2014")
45962
- }, {
45963
- value: "->",
45964
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2192")
45965
- }
45966
- /*
45967
- TODO(eater): fix khan-exercises so these are supported
45968
- {value: "<-", content: <span>&#x2190;</span>},
45969
- {value: "<->", content: <span>&#x2194;</span>}
45970
- */],
45971
-
45972
- onChange: this.props.onChange
45973
- });
45974
- }
45975
- }
45976
-
45977
- const COLORS = [KhanColors.BLACK, KhanColors.BLUE, KhanColors.GREEN, KhanColors.PINK, KhanColors.PURPLE, KhanColors.RED, KhanColors.GRAY];
45978
- const LIGHT_COLORS = [KhanColors.LIGHT_BLUE, KhanColors.LIGHT_ORANGE, KhanColors.LIGHT_PINK, KhanColors.LIGHT_GREEN, KhanColors.LIGHT_PURPLE, KhanColors.LIGHT_RED, "#fff"];
45979
- class ColorPicker extends React__namespace.Component {
45980
- static defaultProps = {
45981
- value: KhanColors.BLACK,
45982
- lightColors: false
45983
- };
45984
- render() {
45985
- const colors = this.props.lightColors ? LIGHT_COLORS : COLORS;
45986
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
45987
- value: this.props.value,
45988
- allowEmpty: false,
45989
- buttons: ___default["default"].map(colors, color => {
45990
- return {
45991
- value: color,
45992
- content: /*#__PURE__*/React__namespace.createElement("span", null, /*#__PURE__*/React__namespace.createElement("span", {
45993
- className: "colorpicker-circle",
45994
- style: {
45995
- background: color
45996
- }
45997
- }), "\xA0")
45998
- };
45999
- }),
46000
- onChange: this.props.onChange
46001
- });
46002
- }
46003
- }
46004
-
46005
- class DashPicker extends React__namespace.Component {
46006
- static defaultProps = {
46007
- value: ""
46008
- };
46009
- render() {
46010
- return /*#__PURE__*/React__namespace.createElement(ButtonGroup, {
46011
- value: this.props.value,
46012
- allowEmpty: false,
46013
- buttons: [{
46014
- value: "",
46015
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2014")
46016
- }, {
46017
- value: "-",
46018
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2013\u2013\u2013")
46019
- }, {
46020
- value: "- ",
46021
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\u2013\xA0\xA0\u2013")
46022
- }, {
46023
- value: ".",
46024
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\xB7\xB7\xB7\xB7")
46025
- }, {
46026
- value: ". ",
46027
- content: /*#__PURE__*/React__namespace.createElement("span", null, "\xB7 \xB7 \xB7")
46028
- }],
46029
- onChange: this.props.onChange
46030
- });
46031
- }
46032
- }
46033
-
46034
- /* eslint-disable jsx-a11y/anchor-is-valid */
46035
- class ElementContainer extends React__namespace.Component {
46036
- static defaultProps = {
46037
- initiallyVisible: false,
46038
- title: "More"
46039
- };
46040
- constructor(props) {
46041
- super(props);
46042
- this.state = {
46043
- show: props.initiallyVisible
46044
- };
46045
- }
46046
- toggle = e => {
46047
- e.preventDefault();
46048
- this.setState({
46049
- show: !this.state.show
46050
- });
46051
- };
46052
- render() {
46053
- return /*#__PURE__*/React__namespace.createElement("div", {
46054
- className: "perseus-interaction-element"
46055
- }, /*#__PURE__*/React__namespace.createElement("a", {
46056
- href: "#",
46057
- className: "perseus-interaction-element-title " + (this.state.show ? "open" : "closed"),
46058
- onClick: this.toggle
46059
- }, this.state.show ? /*#__PURE__*/React__namespace.createElement(InlineIcon, iconChevronDown) : /*#__PURE__*/React__namespace.createElement(InlineIcon, iconChevronRight), this.props.title), /*#__PURE__*/React__namespace.createElement("div", {
46060
- className: "perseus-interaction-element-content " + (this.state.show ? "enter" : "leave")
46061
- }, this.props.children, (this.props.onUp != null || this.props.onDown != null || this.props.onDelete != null) && /*#__PURE__*/React__namespace.createElement("div", {
46062
- className: "edit-controls"
46063
- }, this.props.onUp != null && /*#__PURE__*/React__namespace.createElement("button", {
46064
- onClick: this.props.onUp
46065
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleArrowUp)), this.props.onDown != null && /*#__PURE__*/React__namespace.createElement("button", {
46066
- onClick: this.props.onDown
46067
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconCircleArrowDown)), this.props.onDelete != null && /*#__PURE__*/React__namespace.createElement("button", {
46068
- onClick: this.props.onDelete
46069
- }, /*#__PURE__*/React__namespace.createElement(InlineIcon, iconTrash)))));
46070
- }
46071
- }
46072
-
46073
45869
  const devices = {
46074
45870
  PHONE: "phone",
46075
45871
  TABLET: "tablet",
@@ -48655,17 +48451,13 @@ const EditorJsonify = {
48655
48451
  };
48656
48452
 
48657
48453
  exports.ApiOptions = ApiOptions;
48658
- exports.ArrowPicker = ArrowPicker;
48659
48454
  exports.ArticleRenderer = ArticleRenderer;
48660
48455
  exports.BaseRadio = BaseRadio;
48661
48456
  exports.Categorizer = Categorizer$1;
48662
48457
  exports.Changeable = changeable;
48663
48458
  exports.ClassNames = ClassNames;
48664
- exports.ColorPicker = ColorPicker;
48665
- exports.DashPicker = DashPicker;
48666
48459
  exports.Dependencies = dependencies;
48667
48460
  exports.EditorJsonify = EditorJsonify;
48668
- exports.ElementContainer = ElementContainer;
48669
48461
  exports.Expression = Expression;
48670
48462
  exports.GrapherUtil = util;
48671
48463
  exports.GrapherWidget = Grapher$1;