Skip to content

Commit

Permalink
[Locked Figure Aria] Locked line aria label editor UI (#1684)
Browse files Browse the repository at this point in the history
## Summary:
- Use `locked-figure-aria.tsx` within LockedLineSettings.
- Write the function to auto-generate the locked line
  aria label with its coordinates and visible labels.

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

## Test plan:
`yarn jest packages/perseus-editor/src/widgets/interactive-graph-editor/locked-figures/locked-line-settings.test.tsx`

Storybook
- http://localhost:6006/?path=/story/perseuseditor-widgets-interactive-graph--mafs-with-locked-figure-labels-all-flags
- Confirm that the locked line aria label field is already populated with "Line PQ" (passed in via builder)
- Confirm that pressing "Auto-generate" works with no labels, one label, and multiple labels
- Confirm that updating the aria label in the editor also updates the aria label on the line
  - Check the web inspector to confirm the aria-label text is updated
  - Use a screen reader to confirm the new label is read out

<img width="392" alt="image" src="https://github.com/user-attachments/assets/64c44caa-0fda-4734-849c-fb61e568a6ee">


https://github.com/user-attachments/assets/36738b4f-6524-4034-adbb-52f6cc53cb94

Author: nishasy

Reviewers: benchristel, nishasy, catandthemachines, anakaren-rojas

Required Reviewers:

Approved By: benchristel

Checks: ✅ 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), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ gerald

Pull Request URL: #1684
  • Loading branch information
nishasy authored Sep 30, 2024
1 parent 2d7cada commit 17ebfc0
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/itchy-pears-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": minor
"@khanacademy/perseus-editor": minor
---

[Locked Figure Aria] Locked line aria label editor UI
Original file line number Diff line number Diff line change
Expand Up @@ -550,4 +550,161 @@ describe("LockedLineSettings", () => {
});
});
});

describe("Aria label", () => {
test("Renders with aria label", () => {
// Arrange

// Act
render(
<LockedLineSettings
{...defaultProps}
ariaLabel="Line at (x, y)"
/>,
{wrapper: RenderStateRoot},
);

const input = screen.getByRole("textbox", {name: "Aria label"});

// Assert
expect(input).toHaveValue("Line at (x, y)");
});

test("calls onChangeProps when the aria label is updated", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedLineSettings
{...defaultProps}
ariaLabel={undefined}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

// Act
const input = screen.getByRole("textbox", {name: "Aria label"});
await userEvent.clear(input);
await userEvent.type(input, "A");

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
ariaLabel: "A",
});
});

test("aria label auto-generates with different kind", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedLineSettings
{...defaultProps}
ariaLabel={undefined}
onChangeProps={onChangeProps}
kind="segment"
/>,
{wrapper: RenderStateRoot},
);

// Act
const autoGenButton = screen.getByRole("button", {
name: "Auto-generate",
});
await userEvent.click(autoGenButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
ariaLabel: "Segment from (0, 0) to (2, 2)",
});
});

test("aria label auto-generates (no labels)", async () => {
// Arrange
const onChangeProps = jest.fn();

// Act
render(
<LockedLineSettings
{...defaultProps}
ariaLabel={undefined}
onChangeProps={onChangeProps}
/>,
{wrapper: RenderStateRoot},
);

const autoGenButton = screen.getByRole("button", {
name: "Auto-generate",
});
await userEvent.click(autoGenButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
ariaLabel: "Line from (0, 0) to (2, 2)",
});
});

test("aria label auto-generates (one label)", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedLineSettings
{...defaultProps}
ariaLabel={undefined}
onChangeProps={onChangeProps}
labels={[
{
...defaultLabel,
text: "A",
},
]}
/>,
{wrapper: RenderStateRoot},
);

// Act
const autoGenButton = screen.getByRole("button", {
name: "Auto-generate",
});
await userEvent.click(autoGenButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
ariaLabel: "Line from (0, 0) to (2, 2) with label A",
});
});

test("aria label auto-generates (multiple labels)", async () => {
// Arrange
const onChangeProps = jest.fn();
render(
<LockedLineSettings
{...defaultProps}
ariaLabel={undefined}
onChangeProps={onChangeProps}
labels={[
{
...defaultLabel,
text: "A",
},
{
...defaultLabel,
text: "B",
},
]}
/>,
{wrapper: RenderStateRoot},
);

// Act
const autoGenButton = screen.getByRole("button", {
name: "Auto-generate",
});
await userEvent.click(autoGenButton);

// Assert
expect(onChangeProps).toHaveBeenCalledWith({
ariaLabel: "Line from (0, 0) to (2, 2) with labels A, B",
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import PerseusEditorAccordion from "../../../components/perseus-editor-accordion
import ColorSelect from "./color-select";
import LineStrokeSelect from "./line-stroke-select";
import LineSwatch from "./line-swatch";
import LockedFigureAria from "./locked-figure-aria";
import LockedFigureSettingsActions from "./locked-figure-settings-actions";
import LockedLabelSettings from "./locked-label-settings";
import LockedPointSettings from "./locked-point-settings";
Expand Down Expand Up @@ -56,6 +57,7 @@ const LockedLineSettings = (props: Props) => {
showPoint1,
showPoint2,
labels,
ariaLabel,
onChangeProps,
onMove,
onRemove,
Expand All @@ -69,6 +71,24 @@ const LockedLineSettings = (props: Props) => {
// Check if the line has length 0.
const isInvalid = kvector.equal(point1.coord, point2.coord);

function getPrepopulatedAriaLabel() {
let str = `${capitalizeKind} from (${point1.coord[0]}, ${point1.coord[1]}) to (${point2.coord[0]}, ${point2.coord[1]})`;

if (labels && labels.length > 0) {
str += " with label";
// Make it "with labels" instead of "with label" if there are
// multiple labels.
if (labels.length > 1) {
str += "s";
}

// Separate additional labels with commas.
str += ` ${labels.map((l) => l.text).join(", ")}`;
}

return str;
}

function handleChangePoint(
newPointProps: Partial<LockedPointType>,
index: 0 | 1,
Expand Down Expand Up @@ -243,9 +263,28 @@ const LockedLineSettings = (props: Props) => {
onChangeProps={(newProps) => handleChangePoint(newProps, 1)}
/>

{flags?.["mafs"]?.["locked-figures-aria"] && (
<>
<Strut size={spacing.small_12} />
<View style={styles.horizontalRule} />

<LockedFigureAria
ariaLabel={ariaLabel}
prePopulatedAriaLabel={getPrepopulatedAriaLabel()}
onChangeProps={(newProps) => {
onChangeProps(newProps);
}}
/>
</>
)}

{flags?.["mafs"]?.["locked-line-labels"] && (
<>
<Strut size={spacing.xxxSmall_4} />
<View style={styles.horizontalRule} />
<Strut size={spacing.small_12} />

<LabelMedium>Visible labels</LabelMedium>

{labels?.map((label, labelIndex) => (
<LockedLabelSettings
Expand Down Expand Up @@ -317,8 +356,6 @@ const styles = StyleSheet.create({
alignSelf: "start",
},
horizontalRule: {
marginTop: spacing.small_12,
marginBottom: spacing.xxxSmall_4,
height: 1,
backgroundColor: wbColor.offBlack16,
},
Expand Down

0 comments on commit 17ebfc0

Please sign in to comment.