Skip to content

Commit

Permalink
Let interactive graph components render a screenreader description (#…
Browse files Browse the repository at this point in the history
…1815)

This refactoring will make it easy for each graph subtype (segment, point,
linear-system, etc.) to describe itself to a screenreader.

At this point, no graph actually renders a screenreader description.  Future
PRs will add descriptions for each graph type.

Issue: https://khanacademy.atlassian.net/browse/LEMS-1725

## Test plan:

`yarn test`

Author: benchristel

Reviewers: nishasy, benchristel, #perseus, anakaren-rojas, catandthemachines

Required Reviewers:

Approved By: nishasy

Checks: ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ gerald

Pull Request URL: #1815
  • Loading branch information
benchristel authored Oct 31, 2024
1 parent d6381f7 commit 2c40219
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 81 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-gorillas-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/perseus": patch
---

Internal: Refactor interactive graph components to support whole-graph screenreader descriptions
19 changes: 17 additions & 2 deletions packages/perseus/src/widgets/interactive-graphs/graphs/angle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,26 @@ import {getIntersectionOfRayWithBox} from "./utils";

import type {CollinearTuple} from "../../../perseus-types";
import type {Segment} from "../math/geometry";
import type {AngleGraphState, MafsGraphProps} from "../types";
import type {
AngleGraphState,
Dispatch,
InteractiveGraphElementSuite,
MafsGraphProps,
} from "../types";

type AngleGraphProps = MafsGraphProps<AngleGraphState>;

export function AngleGraph(props: AngleGraphProps) {
export function renderAngleGraph(
state: AngleGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <AngleGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

function AngleGraph(props: AngleGraphProps) {
const {dispatch, graphState} = props;
const {graphDimensionsInPixels} = useGraphConfig();

Expand Down
19 changes: 17 additions & 2 deletions packages/perseus/src/widgets/interactive-graphs/graphs/circle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,26 @@ import {
useTransformVectorsToPixels,
} from "./use-transform";

import type {CircleGraphState, MafsGraphProps} from "../types";
import type {
CircleGraphState,
Dispatch,
InteractiveGraphElementSuite,
MafsGraphProps,
} from "../types";

export function renderCircleGraph(
state: CircleGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <CircleGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type CircleGraphProps = MafsGraphProps<CircleGraphState>;

export function CircleGraph(props: CircleGraphProps) {
function CircleGraph(props: CircleGraphProps) {
const {dispatch, graphState} = props;
const {center, radiusPoint} = graphState;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ import {actions} from "../reducer/interactive-graph-action";

import {MovableLine} from "./components/movable-line";

import type {MafsGraphProps, LinearSystemGraphState} from "../types";
import type {
MafsGraphProps,
LinearSystemGraphState,
Dispatch,
InteractiveGraphElementSuite,
} from "../types";
import type {vec} from "mafs";

export function renderLinearSystemGraph(
state: LinearSystemGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <LinearSystemGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type LinearSystemGraphProps = MafsGraphProps<LinearSystemGraphState>;

export const LinearSystemGraph = (props: LinearSystemGraphProps) => {
const LinearSystemGraph = (props: LinearSystemGraphProps) => {
const {dispatch} = props;
const {coords: lines} = props.graphState;

Expand Down
19 changes: 17 additions & 2 deletions packages/perseus/src/widgets/interactive-graphs/graphs/linear.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ import {actions} from "../reducer/interactive-graph-action";

import {MovableLine} from "./components/movable-line";

import type {MafsGraphProps, LinearGraphState} from "../types";
import type {
MafsGraphProps,
LinearGraphState,
Dispatch,
InteractiveGraphElementSuite,
} from "../types";
import type {vec} from "mafs";

export function renderLinearGraph(
state: LinearGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <LinearGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type LinearGraphProps = MafsGraphProps<LinearGraphState>;

export const LinearGraph = (props: LinearGraphProps, key: number) => {
const LinearGraph = (props: LinearGraphProps, key: number) => {
const {dispatch} = props;
const {coords: line} = props.graphState;

Expand Down
35 changes: 25 additions & 10 deletions packages/perseus/src/widgets/interactive-graphs/graphs/point.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,34 @@ import {
pixelsToVectors,
} from "./use-transform";

import type {PointGraphState, MafsGraphProps} from "../types";
import type {
PointGraphState,
MafsGraphProps,
Dispatch,
InteractiveGraphElementSuite,
} from "../types";

export function renderPointGraph(
state: PointGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <PointGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type PointGraphProps = MafsGraphProps<PointGraphState>;

function PointGraph(props: PointGraphProps) {
const numPoints = props.graphState.numPoints;
if (numPoints === "unlimited") {
return UnlimitedPointGraph(props);
}

return LimitedPointGraph(props);
}

function LimitedPointGraph(props: PointGraphProps) {
const {dispatch} = props;

Expand Down Expand Up @@ -103,12 +127,3 @@ function UnlimitedPointGraph(props: PointGraphProps) {
</>
);
}

export function PointGraph(props: PointGraphProps) {
const numPoints = props.graphState.numPoints;
if (numPoints === "unlimited") {
return UnlimitedPointGraph(props);
}

return LimitedPointGraph(props);
}
23 changes: 19 additions & 4 deletions packages/perseus/src/widgets/interactive-graphs/graphs/polygon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,26 @@ import {useDraggable} from "./use-draggable";
import {pixelsToVectors, useTransformVectorsToPixels} from "./use-transform";

import type {CollinearTuple} from "../../../perseus-types";
import type {MafsGraphProps, PolygonGraphState} from "../types";
import type {
Dispatch,
InteractiveGraphElementSuite,
MafsGraphProps,
PolygonGraphState,
} from "../types";

export function renderPolygonGraph(
state: PolygonGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <PolygonGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type Props = MafsGraphProps<PolygonGraphState>;

export const LimitedPolygonGraph = (props: Props) => {
const LimitedPolygonGraph = (props: Props) => {
const [hovered, setHovered] = React.useState(false);
// This is more so required for the re-rendering that occurs when state
// updates; specifically with regard to line weighting and polygon focus.
Expand Down Expand Up @@ -157,7 +172,7 @@ export const LimitedPolygonGraph = (props: Props) => {
// TODO(catjohnson): reduce redundancy between LimitedPolygonGraph and UnlimitedPolygonGraph
// both components are vary similar, however more implementation is needed to be added before
// it is clear what can and can't be shared between components.
export const UnlimitedPolygonGraph = (props: Props) => {
const UnlimitedPolygonGraph = (props: Props) => {
const [hovered, setHovered] = React.useState(false);
// This is more so required for the re-rendering that occurs when state
// updates; specifically with regard to line weighting and polygon focus.
Expand Down Expand Up @@ -369,7 +384,7 @@ export const hasFocusVisible = (
}
};

export const PolygonGraph = (props: Props) => {
const PolygonGraph = (props: Props) => {
const numSides = props.graphState.numSides;

return numSides === "unlimited"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,28 @@ import {actions} from "../reducer/interactive-graph-action";

import {MovablePoint} from "./components/movable-point";

import type {QuadraticGraphState, MafsGraphProps} from "../types";
import type {
QuadraticGraphState,
MafsGraphProps,
Dispatch,
InteractiveGraphElementSuite,
} from "../types";

export function renderQuadraticGraph(
state: QuadraticGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <QuadraticGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type QuadraticGraphProps = MafsGraphProps<QuadraticGraphState>;
type QuadraticCoefficient = [number, number, number];
export type QuadraticCoords = QuadraticGraphState["coords"];

export function QuadraticGraph(props: QuadraticGraphProps) {
function QuadraticGraph(props: QuadraticGraphProps) {
const {dispatch, graphState} = props;

const {coords} = graphState;
Expand Down
19 changes: 17 additions & 2 deletions packages/perseus/src/widgets/interactive-graphs/graphs/ray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ import {actions} from "../reducer/interactive-graph-action";

import {MovableLine} from "./components/movable-line";

import type {MafsGraphProps, RayGraphState} from "../types";
import type {
Dispatch,
InteractiveGraphElementSuite,
MafsGraphProps,
RayGraphState,
} from "../types";
import type {vec} from "mafs";

export function renderRayGraph(
state: RayGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <RayGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type Props = MafsGraphProps<RayGraphState>;

export const RayGraph = (props: Props) => {
const RayGraph = (props: Props) => {
const {dispatch} = props;
const {coords: line} = props.graphState;

Expand Down
19 changes: 17 additions & 2 deletions packages/perseus/src/widgets/interactive-graphs/graphs/segment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ import {actions} from "../reducer/interactive-graph-action";

import {MovableLine} from "./components/movable-line";

import type {MafsGraphProps, SegmentGraphState} from "../types";
import type {
Dispatch,
InteractiveGraphElementSuite,
MafsGraphProps,
SegmentGraphState,
} from "../types";
import type {vec} from "mafs";

export function renderSegmentGraph(
state: SegmentGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <SegmentGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type SegmentProps = MafsGraphProps<SegmentGraphState>;

export const SegmentGraph = (props: SegmentProps) => {
const SegmentGraph = (props: SegmentProps) => {
const {dispatch} = props;
const {coords: segments} = props.graphState;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,22 @@ import {actions} from "../reducer/interactive-graph-action";
import {MovablePoint} from "./components/movable-point";

import type {Coord} from "../../../interactive2/types";
import type {SinusoidGraphState, MafsGraphProps} from "../types";
import type {
SinusoidGraphState,
MafsGraphProps,
Dispatch,
InteractiveGraphElementSuite,
} from "../types";

export function renderSinusoidGraph(
state: SinusoidGraphState,
dispatch: Dispatch,
): InteractiveGraphElementSuite {
return {
graph: <SinusoidGraph graphState={state} dispatch={dispatch} />,
screenreaderDescription: null,
};
}

type SinusoidGraphProps = MafsGraphProps<SinusoidGraphState>;

Expand All @@ -19,7 +34,7 @@ export type SineCoefficient = {
verticalOffset: number;
};

export function SinusoidGraph(props: SinusoidGraphProps) {
function SinusoidGraph(props: SinusoidGraphProps) {
const {dispatch, graphState} = props;

// Destructure the coordinates from the graph state
Expand Down
Loading

0 comments on commit 2c40219

Please sign in to comment.