diff --git a/.changeset/fresh-sheep-invent.md b/.changeset/fresh-sheep-invent.md new file mode 100644 index 0000000000..18a346681f --- /dev/null +++ b/.changeset/fresh-sheep-invent.md @@ -0,0 +1,6 @@ +--- +"@khanacademy/perseus": minor +"@khanacademy/perseus-editor": minor +--- + +[Locked Figure Aria] Implement locked line aria label behavior on graph diff --git a/packages/perseus/src/perseus-types.ts b/packages/perseus/src/perseus-types.ts index de7930fc6e..99b7dcafb8 100644 --- a/packages/perseus/src/perseus-types.ts +++ b/packages/perseus/src/perseus-types.ts @@ -719,6 +719,7 @@ export type LockedLineType = { showPoint1: boolean; showPoint2: boolean; labels?: LockedLabelType[]; + ariaLabel?: string; }; export type LockedVectorType = { diff --git a/packages/perseus/src/widgets/interactive-graphs/graph-locked-layer.tsx b/packages/perseus/src/widgets/interactive-graphs/graph-locked-layer.tsx index b883cc4216..134ceb7dd0 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graph-locked-layer.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graph-locked-layer.tsx @@ -38,6 +38,7 @@ const GraphLockedLayer = (props: Props) => { key={`line-${index}`} range={props.range} {...figure} + flags={flags} /> ); case "vector": diff --git a/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.test.ts b/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.test.ts index 372a7c4a0c..ca00988816 100644 --- a/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.test.ts +++ b/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.test.ts @@ -867,6 +867,7 @@ describe("InteractiveGraphQuestionBuilder", () => { showPoint1: true, showPoint2: true, labels: [{text: "a label"}], + ariaLabel: "an aria label", }) .build(); const graph = question.widgets["interactive-graph 1"]; @@ -902,6 +903,7 @@ describe("InteractiveGraphQuestionBuilder", () => { size: "medium", }, ], + ariaLabel: "an aria label", }, ]); }); diff --git a/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.ts b/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.ts index 07aff6e25f..fe5b57ca50 100644 --- a/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.ts +++ b/packages/perseus/src/widgets/interactive-graphs/interactive-graph-question-builder.ts @@ -316,6 +316,7 @@ class InteractiveGraphQuestionBuilder { showPoint1?: boolean; showPoint2?: boolean; labels?: LockedFigureLabelOptions[]; + ariaLabel?: string; }, ): InteractiveGraphQuestionBuilder { const line: LockedLineType = { @@ -332,6 +333,7 @@ class InteractiveGraphQuestionBuilder { color: options?.color ?? "grayH", size: label.size ?? "medium", })), + ariaLabel: options?.ariaLabel, points: [ { ...this.createLockedPoint(...point1, { diff --git a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.test.tsx b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.test.tsx index 5653d22331..73c150db45 100644 --- a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.test.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.test.tsx @@ -673,6 +673,52 @@ describe("locked layer", () => { }); }); + it("should render locked line with aria label when one is provided", () => { + // Arrange + const lockedLineWithAriaLabelQuestion = + interactiveGraphQuestionBuilder() + .addLockedLine([0, 0], [2, 2], { + ariaLabel: "Line A", + }) + .build(); + const {container} = renderQuestion(lockedLineWithAriaLabelQuestion, { + flags: { + mafs: { + segment: true, + "locked-figures-aria": true, + }, + }, + }); + + // Act + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const point = container.querySelector(".locked-line"); + + // Assert + expect(point).toHaveAttribute("aria-label", "Line A"); + }); + + it("should render locked line without aria label by default", () => { + // Arrange + const simpleLockedLinequestion = interactiveGraphQuestionBuilder() + .addLockedLine([0, 0], [2, 2]) + .build(); + const {container} = renderQuestion(simpleLockedLinequestion, { + flags: { + mafs: { + segment: true, + }, + }, + }); + + // Act + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const point = container.querySelector(".locked-line"); + + // Assert + expect(point).not.toHaveAttribute("aria-label"); + }); + it("should render locked vectors", async () => { // Arrange const {container} = renderQuestion(segmentWithLockedVectors, { diff --git a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.testdata.ts b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.testdata.ts index c98b171003..09b66bd77f 100644 --- a/packages/perseus/src/widgets/interactive-graphs/interactive-graph.testdata.ts +++ b/packages/perseus/src/widgets/interactive-graphs/interactive-graph.testdata.ts @@ -835,6 +835,7 @@ export const segmentWithLockedFigures: PerseusRenderer = showPoint1: true, showPoint2: true, labels: [{text: "B"}], + ariaLabel: "Line PQ", }) .addLockedVector([0, 0], [8, 2], { color: "purple", diff --git a/packages/perseus/src/widgets/interactive-graphs/locked-figures/locked-line.tsx b/packages/perseus/src/widgets/interactive-graphs/locked-figures/locked-line.tsx index a7d8bfceff..42114fff3b 100644 --- a/packages/perseus/src/widgets/interactive-graphs/locked-figures/locked-line.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/locked-figures/locked-line.tsx @@ -10,17 +10,30 @@ import {getIntersectionOfRayWithBox} from "../graphs/utils"; import {X, Y, calculateAngleInDegrees} from "../math"; import type {LockedLineType} from "../../../perseus-types"; +import type {APIOptions} from "../../../types"; import type {Interval} from "mafs"; type Props = LockedLineType & { + flags?: APIOptions["flags"]; range: [Interval, Interval]; }; const LockedLine = (props: Props) => { - const {color, lineStyle, kind, points, showPoint1, showPoint2, range} = - props; + const { + color, + lineStyle, + kind, + points, + showPoint1, + showPoint2, + ariaLabel, + flags, + range, + } = props; const [point1, point2] = points; + const hasAria = ariaLabel && flags?.["mafs"]?.["locked-figures-aria"]; + let line; if (kind === "ray") { @@ -101,7 +114,11 @@ const LockedLine = (props: Props) => { } return ( - + {line} {showPoint1 && (