-
Notifications
You must be signed in to change notification settings - Fork 350
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Interactive Graph + Editor] Add aria label and description to entire…
… interactive graph and its UI to the editor (#1568) ## Summary: - Add `fullGraphAriaLabel` and `fullGraphAriaDescription` fields to interactive graph. - Hook up the graph so that if the `fullGraphAriaLabel` and/or `fullGraphAriaDescription` fields are present, then the graph has the respective `aria-label` and `aria-describedby` properties. - Add the UI to the interactive graph editor that allows the content author to add a title (label) and description to the graph. Issue: https://khanacademy.atlassian.net/browse/LEMS-2283 ## Test plan: `yarn jest packages/perseus-editor/src/components/__tests__/interactive-graph-description.test.tsx` `yarn jest packages/perseus-editor/src/widgets/__tests__/interactive-graph-editor.test.tsx` `yarn jest packages/perseus/src/widgets/interactive-graphs/interactive-graph.test.tsx` Storybook - Go to http://localhost:6006/iframe.html?id=perseuseditor-widgets-interactive-graph--interactive-graph-with-aria-label&viewMode=story - There should already be a title and description written in their respective fields - Use a screenreader to tab to the graph - Confirm that the title and description are read. They will both be read at once in Safari and Firefox. With Chrome, use the screenreader controls to go to the next element to hear the description. - Change the values in the title and description inputs, and confirm that the aria label and description on the graph updates. ## Demo: https://github.com/user-attachments/assets/3c825e87-a989-4327-8319-2205e8913b4e NOTE! The janky textarea will be replaced with a Wonder Blocks TextArea [soon](https://khanacademy.atlassian.net/browse/LEMS-2332). ![image](https://github.com/user-attachments/assets/a4b6c931-4619-4c71-bb35-542cea6817fd) Author: nishasy Reviewers: benchristel, mark-fitzgerald, catandthemachines, jeremywiebe Required Reviewers: Approved By: benchristel Checks: ✅ codecov/project, ✅ gerald, ✅ Upload Coverage (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), 🚫 Upload Coverage, ✅ gerald, 🚫 Publish npm snapshot (ubuntu-latest, 20.x), 🚫 Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), 🚫 Jest Coverage (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), 🚫 Check builds for changes in size (ubuntu-latest, 20.x), 🚫 Cypress (ubuntu-latest, 20.x), ✅ gerald, ✅ codecov/patch, ✅ Upload Coverage (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: #1568
- Loading branch information
Showing
12 changed files
with
346 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@khanacademy/perseus": minor | ||
"@khanacademy/perseus-editor": minor | ||
--- | ||
|
||
[Interactive Graph + Editor] Add a full graph aria-label and aria-description/describedby to interactive graphs, as well as the UI for content authors to add this in the interactive graph editor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
packages/perseus-editor/src/components/__tests__/interactive-graph-description.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import {Dependencies} from "@khanacademy/perseus"; | ||
import {render, screen} from "@testing-library/react"; | ||
import {userEvent as userEventLib} from "@testing-library/user-event"; | ||
import * as React from "react"; | ||
|
||
import {testDependencies} from "../../../../../testing/test-dependencies"; | ||
import InteractiveGraphDescription from "../interactive-graph-description"; | ||
|
||
import type {UserEvent} from "@testing-library/user-event"; | ||
|
||
import "@testing-library/jest-dom"; // Imports custom matchers | ||
|
||
function userEventForFakeTimers() { | ||
return userEventLib.setup({ | ||
advanceTimers: jest.advanceTimersByTime, | ||
}); | ||
} | ||
|
||
describe("InteractiveGraphSettings", () => { | ||
let userEvent: UserEvent; | ||
beforeEach(() => { | ||
userEvent = userEventForFakeTimers(); | ||
jest.spyOn(Dependencies, "getDependencies").mockReturnValue( | ||
testDependencies, | ||
); | ||
}); | ||
|
||
test("renders", () => { | ||
// Arrange | ||
render( | ||
<InteractiveGraphDescription | ||
ariaLabelValue="Graph Title" | ||
ariaDescriptionValue="Graph Description" | ||
onChange={jest.fn()} | ||
/>, | ||
); | ||
|
||
// Act | ||
const titleInput = screen.getByRole("textbox", {name: "Title"}); | ||
const descriptionInput = screen.getByRole("textbox", { | ||
name: "Description", | ||
}); | ||
|
||
// Assert | ||
expect(titleInput).toBeInTheDocument(); | ||
expect(titleInput).toHaveValue("Graph Title"); | ||
expect(descriptionInput).toBeInTheDocument(); | ||
expect(descriptionInput).toHaveValue("Graph Description"); | ||
}); | ||
|
||
test("calls onChange when the title is changed", async () => { | ||
// Arrange | ||
const onChange = jest.fn(); | ||
render( | ||
<InteractiveGraphDescription | ||
ariaLabelValue="" | ||
ariaDescriptionValue="" | ||
onChange={onChange} | ||
/>, | ||
); | ||
|
||
// Act | ||
const titleInput = screen.getByRole("textbox", {name: "Title"}); | ||
await userEvent.clear(titleInput); | ||
await userEvent.type(titleInput, "Zot"); | ||
|
||
// Assert | ||
// Calls are not being accumulated because they're mocked. | ||
expect(onChange.mock.calls).toEqual([ | ||
[{fullGraphAriaLabel: "Z"}], | ||
[{fullGraphAriaLabel: "o"}], | ||
[{fullGraphAriaLabel: "t"}], | ||
]); | ||
}); | ||
|
||
test("calls onChange when the description is changed", async () => { | ||
// Arrange | ||
const onChange = jest.fn(); | ||
render( | ||
<InteractiveGraphDescription | ||
ariaLabelValue="" | ||
ariaDescriptionValue="" | ||
onChange={onChange} | ||
/>, | ||
); | ||
|
||
// Act | ||
const descriptionInput = screen.getByRole("textbox", { | ||
name: "Description", | ||
}); | ||
await userEvent.clear(descriptionInput); | ||
await userEvent.type(descriptionInput, "Zot"); | ||
|
||
// Assert | ||
// Calls are not being accumulated because they're mocked. | ||
expect(onChange.mock.calls).toEqual([ | ||
[{fullGraphAriaDescription: "Z"}], | ||
[{fullGraphAriaDescription: "o"}], | ||
[{fullGraphAriaDescription: "t"}], | ||
]); | ||
}); | ||
}); |
82 changes: 82 additions & 0 deletions
82
packages/perseus-editor/src/components/interactive-graph-description.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {View} from "@khanacademy/wonder-blocks-core"; | ||
import {TextField} from "@khanacademy/wonder-blocks-form"; | ||
import {Strut} from "@khanacademy/wonder-blocks-layout"; | ||
import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; | ||
import {LabelLarge, LabelXSmall} from "@khanacademy/wonder-blocks-typography"; | ||
import {StyleSheet} from "aphrodite"; | ||
import * as React from "react"; | ||
|
||
import Heading from "./heading"; | ||
|
||
import type {Props as EditorProps} from "../widgets/interactive-graph-editor/interactive-graph-editor"; | ||
|
||
type Props = { | ||
ariaLabelValue: string; | ||
ariaDescriptionValue: string; | ||
onChange: (graphProps: Partial<EditorProps>) => void; | ||
}; | ||
|
||
export default function InteractiveGraphDescription(props: Props) { | ||
const {ariaLabelValue, ariaDescriptionValue, onChange} = props; | ||
|
||
const [isOpen, setIsOpen] = React.useState(true); | ||
|
||
return ( | ||
<> | ||
<Heading | ||
title="Description" | ||
isCollapsible={true} | ||
isOpen={isOpen} | ||
onToggle={setIsOpen} | ||
/> | ||
{isOpen && ( | ||
<View> | ||
<LabelXSmall style={styles.caption}> | ||
Use these fields to describe the graph as a whole. These | ||
are used by screen readers to describe content to users | ||
who are visually impaired. | ||
</LabelXSmall> | ||
<LabelLarge tag="label"> | ||
Title | ||
<TextField | ||
value={ariaLabelValue} | ||
onChange={(newValue) => | ||
onChange({fullGraphAriaLabel: newValue}) | ||
} | ||
/> | ||
</LabelLarge> | ||
<Strut size={spacing.xSmall_8} /> | ||
<LabelLarge | ||
tag="label" | ||
// TODO(LEMS-2332): Remove this style prop after | ||
// switching to WB TextArea | ||
style={{ | ||
display: "flex", | ||
flexDirection: "column", | ||
}} | ||
> | ||
Description | ||
{/* TODO(LEMS-2332): Change this to a WB TextArea */} | ||
<textarea | ||
rows={8} | ||
value={ariaDescriptionValue} | ||
onChange={(e) => | ||
onChange({ | ||
fullGraphAriaDescription: e.target.value, | ||
}) | ||
} | ||
/> | ||
</LabelLarge> | ||
</View> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
caption: { | ||
color: color.offBlack64, | ||
paddingTop: spacing.xxSmall_6, | ||
paddingBottom: spacing.xxSmall_6, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.