@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/index.js CHANGED
@@ -420,6 +420,70 @@ const mockStrings = {
420
420
  point4Y
421
421
  } = _ref32;
422
422
  return `Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`;
423
+ },
424
+ srLinearGraph: "A line on a coordinate plane.",
425
+ srLinearGraphPoints: _ref33 => {
426
+ let {
427
+ point1X,
428
+ point1Y,
429
+ point2X,
430
+ point2Y
431
+ } = _ref33;
432
+ return `The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`;
433
+ },
434
+ srLinearGraphSlopeIncreasing: "Its slope increases from left to right.",
435
+ srLinearGraphSlopeDecreasing: "Its slope decreases from left to right.",
436
+ srLinearGraphSlopeHorizontal: "Its slope is zero.",
437
+ srLinearGraphSlopeVertical: "Its slope is undefined.",
438
+ srLinearGraphXOnlyIntercept: _ref34 => {
439
+ let {
440
+ xIntercept
441
+ } = _ref34;
442
+ return `The line crosses the X-axis at ${xIntercept} comma 0.`;
443
+ },
444
+ srLinearGraphYOnlyIntercept: _ref35 => {
445
+ let {
446
+ yIntercept
447
+ } = _ref35;
448
+ return `The line crosses the Y-axis at 0 comma ${yIntercept}.`;
449
+ },
450
+ srLinearGraphBothIntercepts: _ref36 => {
451
+ let {
452
+ xIntercept,
453
+ yIntercept
454
+ } = _ref36;
455
+ return `The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`;
456
+ },
457
+ srLinearGraphOriginIntercept: "The line crosses the x and y axes at the graph's origin.",
458
+ srAngleSideAtCoordinates: _ref37 => {
459
+ let {
460
+ point,
461
+ side,
462
+ x,
463
+ y
464
+ } = _ref37;
465
+ return `Point ${point}, ${side} at ${x} comma ${y}`;
466
+ },
467
+ srAngleVertexAtCoordinatesWithAngleMeasure: _ref38 => {
468
+ let {
469
+ x,
470
+ y,
471
+ angleMeasure
472
+ } = _ref38;
473
+ return `Point 2, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees`;
474
+ },
475
+ srAngleGraphAriaLabel: "An angle on a coordinate plane.",
476
+ srAngleGraphAriaDescription: _ref39 => {
477
+ let {
478
+ angleMeasure,
479
+ vertexX,
480
+ vertexY,
481
+ isX,
482
+ isY,
483
+ tsX,
484
+ tsY
485
+ } = _ref39;
486
+ return `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}.`;
423
487
  }
424
488
  // The above strings are used for interactive graph SR descriptions.
425
489
  };
@@ -27629,11 +27693,21 @@ class Dropdown extends React__namespace.Component {
27629
27693
  key: "placeholder",
27630
27694
  value: "0",
27631
27695
  disabled: true,
27632
- label: this.props.placeholder || " "
27696
+ label: /*#__PURE__*/React__namespace.createElement(Renderer, {
27697
+ content: this.props.placeholder,
27698
+ strings: this.context.strings,
27699
+ inline: true
27700
+ }),
27701
+ labelAsText: this.props.placeholder
27633
27702
  }), ...this.props.choices.map((choice, i) => /*#__PURE__*/React__namespace.createElement(wonderBlocksDropdown.OptionItem, {
27634
27703
  key: String(i + 1),
27635
27704
  value: String(i + 1),
27636
- label: choice
27705
+ label: /*#__PURE__*/React__namespace.createElement(Renderer, {
27706
+ content: choice,
27707
+ strings: this.context.strings,
27708
+ inline: true
27709
+ }),
27710
+ labelAsText: choice
27637
27711
  }))];
27638
27712
  return /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.Id, null, dropdownId => /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View
27639
27713
  // NOTE(jared): These are required to prevent weird behavior
@@ -27660,7 +27734,8 @@ class Dropdown extends React__namespace.Component {
27660
27734
  // all dropdowns.
27661
27735
  // See https://khanacademy.atlassian.net/browse/WB-1671
27662
27736
  ,
27663
- role: "combobox"
27737
+ role: "combobox",
27738
+ showOpenerLabelAsText: false
27664
27739
  }, children)));
27665
27740
  }
27666
27741
  }
@@ -34119,6 +34194,8 @@ const noop$1 = () => {};
34119
34194
 
34120
34195
  const MovableLine = props => {
34121
34196
  const {
34197
+ ariaLabels,
34198
+ ariaDescribedBy,
34122
34199
  onMoveLine = () => {},
34123
34200
  onMovePoint = () => {},
34124
34201
  color,
@@ -34141,6 +34218,8 @@ const MovableLine = props => {
34141
34218
  visiblePoint: visiblePoint1,
34142
34219
  focusableHandle: focusableHandle1
34143
34220
  } = useControlPoint({
34221
+ ariaLabel: ariaLabels?.point1AriaLabel,
34222
+ ariaDescribedBy: ariaDescribedBy,
34144
34223
  point: start,
34145
34224
  sequenceNumber: 1,
34146
34225
  color,
@@ -34150,6 +34229,8 @@ const MovableLine = props => {
34150
34229
  visiblePoint: visiblePoint2,
34151
34230
  focusableHandle: focusableHandle2
34152
34231
  } = useControlPoint({
34232
+ ariaLabel: ariaLabels?.point2AriaLabel,
34233
+ ariaDescribedBy: ariaDescribedBy,
34153
34234
  point: end,
34154
34235
  sequenceNumber: 2,
34155
34236
  color,
@@ -34330,23 +34411,82 @@ function AngleGraph(props) {
34330
34411
  showAngles: showAngles || false // Whether to show the angle or not
34331
34412
  };
34332
34413
 
34414
+ const {
34415
+ strings,
34416
+ locale
34417
+ } = usePerseusI18n();
34418
+ const angleMeasure = srFormatNumber(getClockwiseAngle([endPoints[0], centerPoint, endPoints[1]], allowReflexAngles), locale);
34419
+ const wholeAngleAriaLabel = strings.srAngleGraphAriaLabel;
34420
+ const wholeAngleDescription = strings.srAngleGraphAriaDescription({
34421
+ angleMeasure,
34422
+ vertexX: srFormatNumber(coords[1][X], locale),
34423
+ vertexY: srFormatNumber(coords[1][Y], locale),
34424
+ isX: srFormatNumber(coords[2][X], locale),
34425
+ isY: srFormatNumber(coords[2][Y], locale),
34426
+ tsX: srFormatNumber(coords[0][X], locale),
34427
+ tsY: srFormatNumber(coords[0][Y], locale)
34428
+ });
34429
+ const formatCoordinates = (x, y) => ({
34430
+ x: srFormatNumber(x, locale),
34431
+ y: srFormatNumber(y, locale)
34432
+ });
34433
+ const formatSideAriaLabel = (side, newPoint) => {
34434
+ const formattedCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
34435
+ const label = side === "terminal" ? strings.srAngleSideAtCoordinates({
34436
+ point: 1,
34437
+ side: "terminal side",
34438
+ ...formattedCoordinates
34439
+ }) : strings.srAngleSideAtCoordinates({
34440
+ point: 3,
34441
+ side: "initial side",
34442
+ ...formattedCoordinates
34443
+ });
34444
+ return label;
34445
+ };
34446
+ const formatVertexAriaLabel = newPoint => {
34447
+ const formattedVertexCoordinates = formatCoordinates(newPoint[X], newPoint[Y]);
34448
+ const label = showAngles ? strings.srAngleVertexAtCoordinatesWithAngleMeasure({
34449
+ ...formattedVertexCoordinates,
34450
+ angleMeasure: angleMeasure
34451
+ }) : strings.srAngleSideAtCoordinates({
34452
+ point: 2,
34453
+ side: "vertex",
34454
+ ...formattedVertexCoordinates
34455
+ });
34456
+ return label;
34457
+ };
34458
+ const initialSideAriaLabel = formatSideAriaLabel("initial", coords[2]);
34459
+ const terminalSideAriaLabel = formatSideAriaLabel("terminal", coords[0]);
34460
+ const vertexAriaLabel = formatVertexAriaLabel(coords[1]);
34461
+
34333
34462
  // Render the lines, angle, and then movable points
34334
- return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, svgLines, /*#__PURE__*/React__namespace.createElement(Angle, angleParams), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
34463
+ return /*#__PURE__*/React__namespace.createElement("g", {
34464
+ "aria-label": wholeAngleAriaLabel,
34465
+ "aria-describedby": "angle-description"
34466
+ }, svgLines, /*#__PURE__*/React__namespace.createElement(Angle, angleParams), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
34335
34467
  point: coords[1],
34336
34468
  sequenceNumber: 1,
34337
34469
  constrain: p => p,
34338
- onMove: destination => dispatch(actions.angle.movePoint(1, destination))
34470
+ onMove: destination => dispatch(actions.angle.movePoint(1, destination)),
34471
+ ariaLabel: vertexAriaLabel
34339
34472
  }), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
34340
34473
  point: coords[0],
34341
34474
  sequenceNumber: 2,
34342
34475
  constrain: getAngleSideConstraint(coords[0], coords[1], snapDegrees || 1),
34343
- onMove: destination => dispatch(actions.angle.movePoint(0, destination))
34476
+ onMove: destination => dispatch(actions.angle.movePoint(0, destination)),
34477
+ ariaLabel: terminalSideAriaLabel
34344
34478
  }), /*#__PURE__*/React__namespace.createElement(MovablePoint$1, {
34345
34479
  point: coords[2],
34346
34480
  sequenceNumber: 3,
34347
34481
  constrain: getAngleSideConstraint(coords[2], coords[1], snapDegrees || 1),
34348
- onMove: destination => dispatch(actions.angle.movePoint(2, destination))
34349
- }));
34482
+ onMove: destination => dispatch(actions.angle.movePoint(2, destination)),
34483
+ ariaLabel: initialSideAriaLabel
34484
+ }), /*#__PURE__*/React__namespace.createElement("g", {
34485
+ id: "angle-description",
34486
+ style: {
34487
+ display: "hidden"
34488
+ }
34489
+ }, wholeAngleDescription));
34350
34490
  }
34351
34491
  const positiveX = [1, 0];
34352
34492
  const negativeX = [-1, 0];
@@ -34704,12 +34844,67 @@ const LinearGraph = (props, key) => {
34704
34844
  const {
34705
34845
  coords: line
34706
34846
  } = props.graphState;
34847
+ const {
34848
+ strings,
34849
+ locale
34850
+ } = usePerseusI18n();
34851
+ const id = React__namespace.useId();
34852
+ const pointsDescriptionId = id + "-points";
34853
+ const interceptDescriptionId = id + "-intercept";
34854
+ const slopeDescriptionId = id + "-slope";
34855
+
34856
+ // Aria label strings
34857
+ const linearGraphPointsDescription = strings.srLinearGraphPoints({
34858
+ point1X: srFormatNumber(line[0][0], locale),
34859
+ point1Y: srFormatNumber(line[0][1], locale),
34860
+ point2X: srFormatNumber(line[1][0], locale),
34861
+ point2Y: srFormatNumber(line[1][1], locale)
34862
+ });
34863
+
34864
+ // Slope description
34865
+ const slope = (line[1][1] - line[0][1]) / (line[1][0] - line[0][0]);
34866
+ let slopeString = "";
34867
+ if (slope === Infinity || slope === -Infinity) {
34868
+ slopeString = strings.srLinearGraphSlopeVertical;
34869
+ } else if (slope === 0) {
34870
+ slopeString = strings.srLinearGraphSlopeHorizontal;
34871
+ } else {
34872
+ slopeString = slope > 0 ? strings.srLinearGraphSlopeIncreasing : strings.srLinearGraphSlopeDecreasing;
34873
+ }
34874
+
34875
+ // Intersection description
34876
+ const xIntercept = (0 - line[0][1]) / slope + line[0][0];
34877
+ const yIntercept = line[0][1] - slope * line[0][0];
34878
+ const hasXIntercept = xIntercept !== Infinity && xIntercept !== -Infinity;
34879
+ const hasYIntercept = yIntercept !== Infinity && yIntercept !== -Infinity;
34880
+ let interceptString;
34881
+ if (hasXIntercept && hasYIntercept) {
34882
+ // Describe both intercepts in the same sentence.
34883
+ interceptString = xIntercept === 0 && yIntercept === 0 ? strings.srLinearGraphOriginIntercept : strings.srLinearGraphBothIntercepts({
34884
+ xIntercept: srFormatNumber(xIntercept, locale),
34885
+ yIntercept: srFormatNumber(yIntercept, locale)
34886
+ });
34887
+ } else {
34888
+ // Describe only one intercept.
34889
+ interceptString = hasXIntercept ? strings.srLinearGraphXOnlyIntercept({
34890
+ xIntercept: srFormatNumber(xIntercept, locale)
34891
+ }) : strings.srLinearGraphYOnlyIntercept({
34892
+ yIntercept: srFormatNumber(yIntercept, locale)
34893
+ });
34894
+ }
34707
34895
 
34708
34896
  // Linear graphs only have one line
34709
34897
  // (LEMS-2050): Update the reducer so that we have a separate action for moving one line
34710
34898
  // and another action for moving multiple lines
34711
- return /*#__PURE__*/React__namespace.createElement(MovableLine, {
34899
+ return /*#__PURE__*/React__namespace.createElement("g", {
34900
+ className: "linear-graph-container"
34901
+ // Outer line minimal description
34902
+ ,
34903
+ "aria-label": strings.srLinearGraph,
34904
+ "aria-describedby": `${pointsDescriptionId} ${interceptDescriptionId} ${slopeDescriptionId}`
34905
+ }, /*#__PURE__*/React__namespace.createElement(MovableLine, {
34712
34906
  key: 0,
34907
+ ariaDescribedBy: `${interceptDescriptionId} ${slopeDescriptionId}`,
34713
34908
  points: line,
34714
34909
  onMoveLine: delta => {
34715
34910
  dispatch(actions.linear.moveLine(delta));
@@ -34720,7 +34915,22 @@ const LinearGraph = (props, key) => {
34720
34915
  },
34721
34916
  onMovePoint: (endpointIndex, destination) => dispatch(actions.linear.movePoint(endpointIndex, destination)),
34722
34917
  color: "var(--movable-line-stroke-color)"
34723
- });
34918
+ }), /*#__PURE__*/React__namespace.createElement("g", {
34919
+ id: pointsDescriptionId,
34920
+ style: {
34921
+ display: "hidden"
34922
+ }
34923
+ }, linearGraphPointsDescription), /*#__PURE__*/React__namespace.createElement("g", {
34924
+ id: interceptDescriptionId,
34925
+ style: {
34926
+ display: "hidden"
34927
+ }
34928
+ }, interceptString), /*#__PURE__*/React__namespace.createElement("g", {
34929
+ id: slopeDescriptionId,
34930
+ style: {
34931
+ display: "hidden"
34932
+ }
34933
+ }, slopeString));
34724
34934
  };
34725
34935
 
34726
34936
  function renderLinearSystemGraph(state, dispatch) {
@@ -45678,7 +45888,7 @@ const init = function () {
45678
45888
 
45679
45889
  // This file is processed by a Rollup plugin (replace) to inject the production
45680
45890
  const libName = "@khanacademy/perseus";
45681
- const libVersion = "49.0.2";
45891
+ const libVersion = "49.1.1";
45682
45892
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
45683
45893
 
45684
45894
  const apiVersion = {