@khanacademy/perseus 49.0.2 → 49.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -281,7 +281,50 @@ const mockStrings = {
281
281
  point3Y,
282
282
  point4X,
283
283
  point4Y
284
- }) => `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`
284
+ }) => `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`,
285
+ srLinearGraph: "A line on a coordinate plane.",
286
+ srLinearGraphPoints: ({
287
+ point1X,
288
+ point1Y,
289
+ point2X,
290
+ point2Y
291
+ }) => `The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`,
292
+ srLinearGraphSlopeIncreasing: "Its slope increases from left to right.",
293
+ srLinearGraphSlopeDecreasing: "Its slope decreases from left to right.",
294
+ srLinearGraphSlopeHorizontal: "Its slope is zero.",
295
+ srLinearGraphSlopeVertical: "Its slope is undefined.",
296
+ srLinearGraphXOnlyIntercept: ({
297
+ xIntercept
298
+ }) => `The line crosses the X-axis at ${xIntercept} comma 0.`,
299
+ srLinearGraphYOnlyIntercept: ({
300
+ yIntercept
301
+ }) => `The line crosses the Y-axis at 0 comma ${yIntercept}.`,
302
+ srLinearGraphBothIntercepts: ({
303
+ xIntercept,
304
+ yIntercept
305
+ }) => `The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`,
306
+ srLinearGraphOriginIntercept: "The line crosses the x and y axes at the graph's origin.",
307
+ srAngleSideAtCoordinates: ({
308
+ point,
309
+ side,
310
+ x,
311
+ y
312
+ }) => `Point ${point}, ${side} at ${x} comma ${y}`,
313
+ srAngleVertexAtCoordinatesWithAngleMeasure: ({
314
+ x,
315
+ y,
316
+ angleMeasure
317
+ }) => `Point 2, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees`,
318
+ srAngleGraphAriaLabel: "An angle on a coordinate plane.",
319
+ srAngleGraphAriaDescription: ({
320
+ angleMeasure,
321
+ vertexX,
322
+ vertexY,
323
+ isX,
324
+ isY,
325
+ tsX,
326
+ tsY
327
+ }) => `The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the initial side at ${isX} comma ${isY} and a point on the terminal side at ${tsX} comma ${tsY}.`
285
328
  // The above strings are used for interactive graph SR descriptions.
286
329
  };
287
330
 
@@ -27376,11 +27419,21 @@ class Dropdown extends React.Component {
27376
27419
  key: "placeholder",
27377
27420
  value: "0",
27378
27421
  disabled: true,
27379
- label: this.props.placeholder || " "
27422
+ label: /*#__PURE__*/React.createElement(Renderer, {
27423
+ content: this.props.placeholder,
27424
+ strings: this.context.strings,
27425
+ inline: true
27426
+ }),
27427
+ labelAsText: this.props.placeholder
27380
27428
  }), ...this.props.choices.map((choice, i) => /*#__PURE__*/React.createElement(OptionItem, {
27381
27429
  key: String(i + 1),
27382
27430
  value: String(i + 1),
27383
- label: choice
27431
+ label: /*#__PURE__*/React.createElement(Renderer, {
27432
+ content: choice,
27433
+ strings: this.context.strings,
27434
+ inline: true
27435
+ }),
27436
+ labelAsText: choice
27384
27437
  }))];
27385
27438
  return /*#__PURE__*/React.createElement(Id, null, dropdownId => /*#__PURE__*/React.createElement(View
27386
27439
  // NOTE(jared): These are required to prevent weird behavior
@@ -27407,7 +27460,8 @@ class Dropdown extends React.Component {
27407
27460
  // all dropdowns.
27408
27461
  // See https://khanacademy.atlassian.net/browse/WB-1671
27409
27462
  ,
27410
- role: "combobox"
27463
+ role: "combobox",
27464
+ showOpenerLabelAsText: false
27411
27465
  }, children)));
27412
27466
  }
27413
27467
  }
@@ -33817,6 +33871,8 @@ const noop$1 = () => {};
33817
33871
 
33818
33872
  const MovableLine = props => {
33819
33873
  const {
33874
+ ariaLabels,
33875
+ ariaDescribedBy,
33820
33876
  onMoveLine = () => {},
33821
33877
  onMovePoint = () => {},
33822
33878
  color,
@@ -33839,6 +33895,8 @@ const MovableLine = props => {
33839
33895
  visiblePoint: visiblePoint1,
33840
33896
  focusableHandle: focusableHandle1
33841
33897
  } = useControlPoint({
33898
+ ariaLabel: ariaLabels == null ? void 0 : ariaLabels.point1AriaLabel,
33899
+ ariaDescribedBy: ariaDescribedBy,
33842
33900
  point: start,
33843
33901
  sequenceNumber: 1,
33844
33902
  color,
@@ -33848,6 +33906,8 @@ const MovableLine = props => {
33848
33906
  visiblePoint: visiblePoint2,
33849
33907
  focusableHandle: focusableHandle2
33850
33908
  } = useControlPoint({
33909
+ ariaLabel: ariaLabels == null ? void 0 : ariaLabels.point2AriaLabel,
33910
+ ariaDescribedBy: ariaDescribedBy,
33851
33911
  point: end,
33852
33912
  sequenceNumber: 2,
33853
33913
  color,
@@ -34026,23 +34086,78 @@ function AngleGraph(props) {
34026
34086
  showAngles: showAngles || false // Whether to show the angle or not
34027
34087
  };
34028
34088
 
34089
+ const {
34090
+ strings,
34091
+ locale
34092
+ } = usePerseusI18n();
34093
+ const angleMeasure = srFormatNumber(getClockwiseAngle([endPoints[0], centerPoint, endPoints[1]], allowReflexAngles), locale);
34094
+ const wholeAngleAriaLabel = strings.srAngleGraphAriaLabel;
34095
+ const wholeAngleDescription = strings.srAngleGraphAriaDescription({
34096
+ angleMeasure,
34097
+ vertexX: srFormatNumber(coords[1][X], locale),
34098
+ vertexY: srFormatNumber(coords[1][Y], locale),
34099
+ isX: srFormatNumber(coords[2][X], locale),
34100
+ isY: srFormatNumber(coords[2][Y], locale),
34101
+ tsX: srFormatNumber(coords[0][X], locale),
34102
+ tsY: srFormatNumber(coords[0][Y], locale)
34103
+ });
34104
+ const formatCoordinates = (x, y) => ({
34105
+ x: srFormatNumber(x, locale),
34106
+ y: srFormatNumber(y, locale)
34107
+ });
34108
+ const formatSideAriaLabel = (side, newPoint) => {
34109
+ const formattedCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
34110
+ const label = side === "terminal" ? strings.srAngleSideAtCoordinates(_extends({
34111
+ point: 1,
34112
+ side: "terminal side"
34113
+ }, formattedCoordinates)) : strings.srAngleSideAtCoordinates(_extends({
34114
+ point: 3,
34115
+ side: "initial side"
34116
+ }, formattedCoordinates));
34117
+ return label;
34118
+ };
34119
+ const formatVertexAriaLabel = newPoint => {
34120
+ const formattedVertexCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
34121
+ const label = showAngles ? strings.srAngleVertexAtCoordinatesWithAngleMeasure(_extends({}, formattedVertexCoordinates, {
34122
+ angleMeasure: angleMeasure
34123
+ })) : strings.srAngleSideAtCoordinates(_extends({
34124
+ point: 2,
34125
+ side: "vertex"
34126
+ }, formattedVertexCoordinates));
34127
+ return label;
34128
+ };
34129
+ const initialSideAriaLabel = formatSideAriaLabel("initial", coords[2]);
34130
+ const terminalSideAriaLabel = formatSideAriaLabel("terminal", coords[0]);
34131
+ const vertexAriaLabel = formatVertexAriaLabel(coords[1]);
34132
+
34029
34133
  // Render the lines, angle, and then movable points
34030
- return /*#__PURE__*/React.createElement(React.Fragment, null, svgLines, /*#__PURE__*/React.createElement(Angle, angleParams), /*#__PURE__*/React.createElement(MovablePoint$1, {
34134
+ return /*#__PURE__*/React.createElement("g", {
34135
+ "aria-label": wholeAngleAriaLabel,
34136
+ "aria-describedby": "angle-description"
34137
+ }, svgLines, /*#__PURE__*/React.createElement(Angle, angleParams), /*#__PURE__*/React.createElement(MovablePoint$1, {
34031
34138
  point: coords[1],
34032
34139
  sequenceNumber: 1,
34033
34140
  constrain: p => p,
34034
- onMove: destination => dispatch(actions.angle.movePoint(1, destination))
34141
+ onMove: destination => dispatch(actions.angle.movePoint(1, destination)),
34142
+ ariaLabel: vertexAriaLabel
34035
34143
  }), /*#__PURE__*/React.createElement(MovablePoint$1, {
34036
34144
  point: coords[0],
34037
34145
  sequenceNumber: 2,
34038
34146
  constrain: getAngleSideConstraint(coords[0], coords[1], snapDegrees || 1),
34039
- onMove: destination => dispatch(actions.angle.movePoint(0, destination))
34147
+ onMove: destination => dispatch(actions.angle.movePoint(0, destination)),
34148
+ ariaLabel: terminalSideAriaLabel
34040
34149
  }), /*#__PURE__*/React.createElement(MovablePoint$1, {
34041
34150
  point: coords[2],
34042
34151
  sequenceNumber: 3,
34043
34152
  constrain: getAngleSideConstraint(coords[2], coords[1], snapDegrees || 1),
34044
- onMove: destination => dispatch(actions.angle.movePoint(2, destination))
34045
- }));
34153
+ onMove: destination => dispatch(actions.angle.movePoint(2, destination)),
34154
+ ariaLabel: initialSideAriaLabel
34155
+ }), /*#__PURE__*/React.createElement("g", {
34156
+ id: "angle-description",
34157
+ style: {
34158
+ display: "hidden"
34159
+ }
34160
+ }, wholeAngleDescription));
34046
34161
  }
34047
34162
  const positiveX = [1, 0];
34048
34163
  const negativeX = [-1, 0];
@@ -34387,12 +34502,67 @@ const LinearGraph = (props, key) => {
34387
34502
  const {
34388
34503
  coords: line
34389
34504
  } = props.graphState;
34505
+ const {
34506
+ strings,
34507
+ locale
34508
+ } = usePerseusI18n();
34509
+ const id = React.useId();
34510
+ const pointsDescriptionId = id + "-points";
34511
+ const interceptDescriptionId = id + "-intercept";
34512
+ const slopeDescriptionId = id + "-slope";
34513
+
34514
+ // Aria label strings
34515
+ const linearGraphPointsDescription = strings.srLinearGraphPoints({
34516
+ point1X: srFormatNumber(line[0][0], locale),
34517
+ point1Y: srFormatNumber(line[0][1], locale),
34518
+ point2X: srFormatNumber(line[1][0], locale),
34519
+ point2Y: srFormatNumber(line[1][1], locale)
34520
+ });
34521
+
34522
+ // Slope description
34523
+ const slope = (line[1][1] - line[0][1]) / (line[1][0] - line[0][0]);
34524
+ let slopeString = "";
34525
+ if (slope === Infinity || slope === -Infinity) {
34526
+ slopeString = strings.srLinearGraphSlopeVertical;
34527
+ } else if (slope === 0) {
34528
+ slopeString = strings.srLinearGraphSlopeHorizontal;
34529
+ } else {
34530
+ slopeString = slope > 0 ? strings.srLinearGraphSlopeIncreasing : strings.srLinearGraphSlopeDecreasing;
34531
+ }
34532
+
34533
+ // Intersection description
34534
+ const xIntercept = (0 - line[0][1]) / slope + line[0][0];
34535
+ const yIntercept = line[0][1] - slope * line[0][0];
34536
+ const hasXIntercept = xIntercept !== Infinity && xIntercept !== -Infinity;
34537
+ const hasYIntercept = yIntercept !== Infinity && yIntercept !== -Infinity;
34538
+ let interceptString;
34539
+ if (hasXIntercept && hasYIntercept) {
34540
+ // Describe both intercepts in the same sentence.
34541
+ interceptString = xIntercept === 0 && yIntercept === 0 ? strings.srLinearGraphOriginIntercept : strings.srLinearGraphBothIntercepts({
34542
+ xIntercept: srFormatNumber(xIntercept, locale),
34543
+ yIntercept: srFormatNumber(yIntercept, locale)
34544
+ });
34545
+ } else {
34546
+ // Describe only one intercept.
34547
+ interceptString = hasXIntercept ? strings.srLinearGraphXOnlyIntercept({
34548
+ xIntercept: srFormatNumber(xIntercept, locale)
34549
+ }) : strings.srLinearGraphYOnlyIntercept({
34550
+ yIntercept: srFormatNumber(yIntercept, locale)
34551
+ });
34552
+ }
34390
34553
 
34391
34554
  // Linear graphs only have one line
34392
34555
  // (LEMS-2050): Update the reducer so that we have a separate action for moving one line
34393
34556
  // and another action for moving multiple lines
34394
- return /*#__PURE__*/React.createElement(MovableLine, {
34557
+ return /*#__PURE__*/React.createElement("g", {
34558
+ className: "linear-graph-container"
34559
+ // Outer line minimal description
34560
+ ,
34561
+ "aria-label": strings.srLinearGraph,
34562
+ "aria-describedby": `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`
34563
+ }, /*#__PURE__*/React.createElement(MovableLine, {
34395
34564
  key: 0,
34565
+ ariaDescribedBy: `${interceptDescriptionId} ${slopeDescriptionId}`,
34396
34566
  points: line,
34397
34567
  onMoveLine: delta => {
34398
34568
  dispatch(actions.linear.moveLine(delta));
@@ -34403,7 +34573,22 @@ const LinearGraph = (props, key) => {
34403
34573
  },
34404
34574
  onMovePoint: (endpointIndex, destination) => dispatch(actions.linear.movePoint(endpointIndex, destination)),
34405
34575
  color: "var(--movable-line-stroke-color)"
34406
- });
34576
+ }), /*#__PURE__*/React.createElement("g", {
34577
+ id: pointsDescriptionId,
34578
+ style: {
34579
+ display: "hidden"
34580
+ }
34581
+ }, linearGraphPointsDescription), /*#__PURE__*/React.createElement("g", {
34582
+ id: interceptDescriptionId,
34583
+ style: {
34584
+ display: "hidden"
34585
+ }
34586
+ }, interceptString), /*#__PURE__*/React.createElement("g", {
34587
+ id: slopeDescriptionId,
34588
+ style: {
34589
+ display: "hidden"
34590
+ }
34591
+ }, slopeString));
34407
34592
  };
34408
34593
 
34409
34594
  function renderLinearSystemGraph(state, dispatch) {
@@ -45322,7 +45507,7 @@ const init = function init() {
45322
45507
 
45323
45508
  // This file is processed by a Rollup plugin (replace) to inject the production
45324
45509
  const libName = "@khanacademy/perseus";
45325
- const libVersion = "49.0.2";
45510
+ const libVersion = "49.1.1";
45326
45511
  addLibraryVersionToPerseusDebug(libName, libVersion);
45327
45512
 
45328
45513
  const apiVersion = {