Skip to content

Commit

Permalink
[Hint Mode: Start Coords] Add start coords UI for point graphs (limit…
Browse files Browse the repository at this point in the history
…ed only) (#1486)

## Summary:
Add the UI to specify start coords for Point graph type.

- Add the point graph type to start-coord-settings.tsx
- Create a start-coords-point.tsx file with the main UI
- Add the start coords UI point flag
- Move the logic for determining whether the UI should be
  shown based on the feature flags out into the util file.

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

## Test plan:
`yarn jest`

Storybook
- http://localhost:6006/?path=/story/perseuseditor-widgets-interactive-graph--interactive-graph-point

<img width="381" alt="image" src="https://github.com/user-attachments/assets/9785deae-e886-4ec9-b2c5-f9eb22384f5f">

Author: nishasy

Reviewers: nishasy, benchristel, Myranae

Required Reviewers:

Approved By: benchristel

Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage (ubuntu-latest, 20.x), ✅ gerald, ⏭️  Publish npm snapshot, ✅ Lint, Typecheck, Format, and Test (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), ✅ Cypress (ubuntu-latest, 20.x), 🚫 Upload Coverage, ✅ gerald, ⏭️  Publish npm snapshot, ✅ 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), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ gerald

Pull Request URL: #1486
  • Loading branch information
nishasy authored Aug 5, 2024
1 parent f920a4c commit 0b625f5
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 26 deletions.
6 changes: 6 additions & 0 deletions .changeset/tasty-eggs-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@khanacademy/perseus": minor
"@khanacademy/perseus-editor": minor
---

[Hint Mode: Start Coords] Add start coords UI for point graphs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const flags = {
// TODO(LEMS-2228): Remove flags once this is fully released
"start-coords-ui-phase-1": true,
"start-coords-ui-phase-2": true,
"start-coords-ui-point": true,
},
} satisfies APIOptions["flags"];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,4 +523,87 @@ describe("StartCoordSettings", () => {
},
);
});

describe("point graph", () => {
test("shows the start coordinates UI: 1 point (default)", () => {
// Arrange

// Act
render(
<StartCoordsSettings
{...defaultProps}
type="point"
onChange={() => {}}
/>,
{wrapper: RenderStateRoot},
);

// Assert
expect(screen.getByText("Start coordinates")).toBeInTheDocument();
expect(screen.getByText("Point 1:")).toBeInTheDocument();
});

test("shows the start coordinates UI: 6 points", () => {
// Arrange

// Act
render(
<StartCoordsSettings
{...defaultProps}
type="point"
numPoints={6}
onChange={() => {}}
/>,
{wrapper: RenderStateRoot},
);

// Assert
expect(screen.getByText("Start coordinates")).toBeInTheDocument();
expect(screen.getByText("Point 1:")).toBeInTheDocument();
expect(screen.getByText("Point 2:")).toBeInTheDocument();
expect(screen.getByText("Point 3:")).toBeInTheDocument();
expect(screen.getByText("Point 4:")).toBeInTheDocument();
expect(screen.getByText("Point 5:")).toBeInTheDocument();
expect(screen.getByText("Point 6:")).toBeInTheDocument();
});

test.each`
pointIndex | coord
${0} | ${"x"}
${0} | ${"y"}
${1} | ${"x"}
${1} | ${"y"}
`(
"calls onChange when $coord coord is changed (line $pointIndex)",
async ({pointIndex, coord}) => {
// Arrange
const onChangeMock = jest.fn();

// Act
render(
<StartCoordsSettings
{...defaultProps}
type="point"
numPoints={2}
onChange={onChangeMock}
/>,
);

// Assert
const input = screen.getAllByRole("spinbutton", {
name: `${coord}`,
})[pointIndex];
await userEvent.clear(input);
await userEvent.type(input, "101");

const expectedCoords = [
[-5, 0],
[5, 0],
];
expectedCoords[pointIndex][coord === "x" ? 0 : 1] = 101;

expect(onChangeMock).toHaveBeenLastCalledWith(expectedCoords);
},
);
});
});
70 changes: 70 additions & 0 deletions packages/perseus-editor/src/components/__tests__/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,76 @@ describe("getDefaultGraphStartCoords", () => {

expect(defaultCoords).toEqual({center: [0, 0], radius: 2});
});

test("should get default start coords for a sinusoid graph", () => {
// Arrange
const graph: PerseusGraphType = {type: "sinusoid"};
const range = [
[-10, 10],
[-10, 10],
] satisfies [Range, Range];
const step = [1, 1] satisfies [number, number];

// Act
const defaultCoords = getDefaultGraphStartCoords(graph, range, step);

expect(defaultCoords).toEqual([
[0, 0],
[3, 2],
]);
});

test("should get default start coords for a quadratic graph", () => {
// Arrange
const graph: PerseusGraphType = {type: "quadratic"};
const range = [
[-10, 10],
[-10, 10],
] satisfies [Range, Range];
const step = [1, 1] satisfies [number, number];

// Act
const defaultCoords = getDefaultGraphStartCoords(graph, range, step);

expect(defaultCoords).toEqual([
[-5, 5],
[0, -5],
[5, 5],
]);
});

test("should get default start coords for a point graph", () => {
// Arrange
const graph: PerseusGraphType = {type: "point"};
const range = [
[-10, 10],
[-10, 10],
] satisfies [Range, Range];
const step = [1, 1] satisfies [number, number];

// Act
const defaultCoords = getDefaultGraphStartCoords(graph, range, step);

expect(defaultCoords).toEqual([[0, 0]]);
});

test("should get default start coords for a point graph with multiple points", () => {
// Arrange
const graph: PerseusGraphType = {type: "point", numPoints: 2};
const range = [
[-10, 10],
[-10, 10],
] satisfies [Range, Range];
const step = [1, 1] satisfies [number, number];

// Act
const defaultCoords = getDefaultGraphStartCoords(graph, range, step);

expect(defaultCoords).toEqual([
[-5, 0],
[5, 0],
]);
});
});

describe("getSinusoidEquation", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ type Props = {
center: Coord;
radius: number;
};
// center: number;
onChange: (startCoords: PerseusGraphType["startCoords"]) => void;
};

Expand Down
54 changes: 54 additions & 0 deletions packages/perseus-editor/src/components/start-coords-point.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {View} from "@khanacademy/wonder-blocks-core";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import {color, spacing} from "@khanacademy/wonder-blocks-tokens";
import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
import {StyleSheet} from "aphrodite";
import * as React from "react";

import CoordinatePairInput from "./coordinate-pair-input";

import type {Coord, PerseusGraphType} from "@khanacademy/perseus";

type Props = {
startCoords: ReadonlyArray<Coord>;
onChange: (startCoords: PerseusGraphType["startCoords"]) => void;
};

const StartCoordsPoint = (props: Props) => {
const {startCoords, onChange} = props;

return (
<>
{startCoords.map((coord, index) => {
return (
<View key={index} style={styles.tile}>
<LabelLarge>{`Point ${index + 1}:`}</LabelLarge>
<Strut size={spacing.small_12} />
<CoordinatePairInput
coord={coord}
labels={["x", "y"]}
onChange={(newCoord) => {
const newStartCoords = [...startCoords];
newStartCoords[index] = newCoord;
onChange(newStartCoords);
}}
/>
</View>
);
})}
</>
);
};

const styles = StyleSheet.create({
tile: {
backgroundColor: color.fadedBlue8,
marginTop: spacing.xSmall_8,
padding: spacing.small_12,
borderRadius: spacing.xSmall_8,
flexDirection: "row",
alignItems: "center",
},
});

export default StartCoordsPoint;
10 changes: 10 additions & 0 deletions packages/perseus-editor/src/components/start-coords-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getCircleCoords,
getLineCoords,
getLinearSystemCoords,
getPointCoords,
getQuadraticCoords,
getSegmentCoords,
getSinusoidCoords,
Expand All @@ -18,6 +19,7 @@ import Heading from "./heading";
import StartCoordsCircle from "./start-coords-circle";
import StartCoordsLine from "./start-coords-line";
import StartCoordsMultiline from "./start-coords-multiline";
import StartCoordsPoint from "./start-coords-point";
import StartCoordsQuadratic from "./start-coords-quadratic";
import StartCoordsSinusoid from "./start-coords-sinusoid";
import {getDefaultGraphStartCoords} from "./util";
Expand Down Expand Up @@ -89,6 +91,14 @@ const StartCoordsSettingsInner = (props: Props) => {
onChange={onChange}
/>
);
case "point":
const pointCoords = getPointCoords(props, range, step);
return (
<StartCoordsPoint
startCoords={pointCoords}
onChange={onChange}
/>
);
default:
return null;
}
Expand Down
41 changes: 41 additions & 0 deletions packages/perseus-editor/src/components/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getCircleCoords,
getLineCoords,
getLinearSystemCoords,
getPointCoords,
getQuadraticCoords,
getSegmentCoords,
getSinusoidCoords,
Expand Down Expand Up @@ -194,6 +195,12 @@ export function getDefaultGraphStartCoords(
range,
step,
);
case "point":
return getPointCoords(
{...graph, startCoords: undefined},
range,
step,
);
default:
return undefined;
}
Expand Down Expand Up @@ -253,3 +260,37 @@ export const getQuadraticEquation = (startCoords: [Coord, Coord, Coord]) => {
"y = " + a.toFixed(3) + "x^2 + " + b.toFixed(3) + "x + " + c.toFixed(3)
);
};

export const shouldShowStartCoordsUI = (flags, graph) => {
// TODO(LEMS-2228): Remove flags once this is fully released
const startCoordsUiPhase1Types = [
"linear",
"linear-system",
"ray",
"segment",
"circle",
];
const startCoordsUiPhase2Types = ["sinusoid", "quadratic"];

const startCoordsPhase1 = flags?.mafs?.["start-coords-ui-phase-1"];
const startCoordsPhase2 = flags?.mafs?.["start-coords-ui-phase-2"];
const startCoordsPoint = flags?.mafs?.["start-coords-ui-point"];

if (startCoordsPhase1 && startCoordsUiPhase1Types.includes(graph.type)) {
return true;
}

if (startCoordsPhase2 && startCoordsUiPhase2Types.includes(graph.type)) {
return true;
}

if (
startCoordsPoint &&
graph.type === "point" &&
graph.numPoints !== "unlimited"
) {
return true;
}

return false;
};
Loading

0 comments on commit 0b625f5

Please sign in to comment.