diff --git a/.changeset/eleven-paws-serve.md b/.changeset/eleven-paws-serve.md
new file mode 100644
index 0000000000..96aa3c3e29
--- /dev/null
+++ b/.changeset/eleven-paws-serve.md
@@ -0,0 +1,6 @@
+---
+"@khanacademy/perseus": minor
+"@khanacademy/perseus-editor": minor
+---
+
+[Hint Mode: Start Coords] Build the foundation for adding start coords UI for angle graphs
diff --git a/.changeset/flat-badgers-matter.md b/.changeset/flat-badgers-matter.md
new file mode 100644
index 0000000000..94e88f9f4e
--- /dev/null
+++ b/.changeset/flat-badgers-matter.md
@@ -0,0 +1,5 @@
+---
+"@khanacademy/math-input": patch
+---
+
+Remove old buttons that we weren't using anymore
diff --git a/.changeset/strange-trains-unite.md b/.changeset/strange-trains-unite.md
new file mode 100644
index 0000000000..cebdd4074d
--- /dev/null
+++ b/.changeset/strange-trains-unite.md
@@ -0,0 +1,5 @@
+---
+"@khanacademy/math-input": patch
+---
+
+Remove unused buttons from MathInput; add Lato
diff --git a/.storybook/main.ts b/.storybook/main.ts
index 4a814f3d38..ea5272561d 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -72,6 +72,7 @@ const config: StorybookConfig = {
docs: {
autodocs: true,
},
+ staticDirs: ["../static"],
};
export default config;
diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html
new file mode 100644
index 0000000000..8b04d3a37d
--- /dev/null
+++ b/.storybook/preview-head.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/math-input/src/components/key-handlers/key-translator.ts b/packages/math-input/src/components/key-handlers/key-translator.ts
index 88f9785695..adf4ea762e 100644
--- a/packages/math-input/src/components/key-handlers/key-translator.ts
+++ b/packages/math-input/src/components/key-handlers/key-translator.ts
@@ -93,7 +93,6 @@ export const getKeyTranslator = (
LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
SQRT: buildGenericCallback("sqrt", ActionType.CMD),
- PHI: buildGenericCallback("\\phi", ActionType.CMD),
PI: buildGenericCallback("pi", ActionType.CMD),
THETA: buildGenericCallback("theta", ActionType.CMD),
RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
@@ -119,14 +118,6 @@ export const getKeyTranslator = (
}
},
- LOG_B: (mathQuill) => {
- mathQuill.typedText("log_");
- mathQuill.keystroke("Right");
- mathQuill.typedText("(");
- mathQuill.keystroke("Left");
- mathQuill.keystroke("Left");
- },
-
LOG_N: (mathQuill) => {
mathQuill.write("log_{ }\\left(\\right)");
mathQuill.keystroke("Left"); // into parentheses
@@ -134,28 +125,9 @@ export const getKeyTranslator = (
mathQuill.keystroke("Left"); // into index
},
- NTHROOT3: (mathQuill) => {
- mathQuill.typedText("nthroot3");
- mathQuill.keystroke("Right");
- },
-
- POW: (mathQuill) => {
- const contents = mathQuill.latex();
- mathQuill.typedText("^");
-
- // If the input hasn't changed (for example, if we're
- // attempting to add an exponent on an empty input or an empty
- // denominator), insert our own "a^b"
- if (mathQuill.latex() === contents) {
- mathQuill.typedText("a^b");
- }
- },
-
// These need to be overwritten by the consumer
// if they're going to be used
DISMISS: () => {},
- NOOP: () => {},
- MANY: () => {},
NUM_0: buildGenericCallback("0"),
NUM_1: buildGenericCallback("1"),
diff --git a/packages/math-input/src/components/keypad/button-assets.tsx b/packages/math-input/src/components/keypad/button-assets.tsx
index a8027f9919..e27d39368f 100644
--- a/packages/math-input/src/components/keypad/button-assets.tsx
+++ b/packages/math-input/src/components/keypad/button-assets.tsx
@@ -1837,42 +1837,6 @@ export default function ButtonAsset({id}: Props): React.ReactElement {
);
-
- /**
- * ANYTHING BELOW IS NOT YET HANDLED
- */
- case "MANY":
- case "NOOP":
- case "PHI":
- case "NTHROOT3":
- case "POW":
- case "LOG_B":
- // placeholder
- return (
-
- );
default:
// this line forces an exhaustive check of all keys;
// if a key is not handled, the compiler will complain.
diff --git a/packages/math-input/src/data/key-configs.ts b/packages/math-input/src/data/key-configs.ts
index bb2549b489..5ef9a03c4f 100644
--- a/packages/math-input/src/data/key-configs.ts
+++ b/packages/math-input/src/data/key-configs.ts
@@ -272,12 +272,6 @@ const KeyConfigs = (
ariaLabel: strings.theta,
}),
},
- NOOP: {
- ...getDefaultOperatorFields({
- key: "NOOP",
- keyType: "EMPTY",
- }),
- },
// Input navigation
UP: {
...getDefaultOperatorFields({
@@ -366,14 +360,6 @@ const KeyConfigs = (
}),
},
- // TODO(charlie): Use the numeral color for the 'Many' key.
- MANY: {
- ...getDefaultOperatorFields({
- key: "MANY",
- keyType: "MANY",
- }),
- },
-
// NUMBERS
NUM_0: {
...getDefaultNumberFields({
@@ -687,26 +673,6 @@ const KeyConfigs = (
key: "z",
}),
},
- PHI: {
- ...getDefaultValueFields({
- key: "PHI",
- }),
- },
- NTHROOT3: {
- ...getDefaultValueFields({
- key: "NTHROOT3",
- }),
- },
- POW: {
- ...getDefaultValueFields({
- key: "POW",
- }),
- },
- LOG_B: {
- ...getDefaultValueFields({
- key: "LOG_B",
- }),
- },
});
export default KeyConfigs;
diff --git a/packages/math-input/src/data/keys.ts b/packages/math-input/src/data/keys.ts
index dffeea5fb5..b118107844 100644
--- a/packages/math-input/src/data/keys.ts
+++ b/packages/math-input/src/data/keys.ts
@@ -45,8 +45,6 @@ export const KeyArray = [
"JUMP_INTO_NUMERATOR",
"JUMP_OUT_NUMERATOR",
"JUMP_OUT_DENOMINATOR", // Multi-functional keys.
- "NOOP", // mobile native only
- "MANY", // A custom key that captures an arbitrary number of symbols but has no 'default' symbol or action.
"NUM_0",
"NUM_1",
"NUM_2",
@@ -109,13 +107,6 @@ export const KeyArray = [
"X",
"Y",
"Z",
-
- // Currently only used by
- // Perseus' Expression MathInput
- "PHI",
- "NTHROOT3",
- "POW",
- "LOG_B",
] as const;
type Key = (typeof KeyArray)[number];
diff --git a/packages/math-input/src/enums.ts b/packages/math-input/src/enums.ts
index 219167d0bd..0908fe9ad2 100644
--- a/packages/math-input/src/enums.ts
+++ b/packages/math-input/src/enums.ts
@@ -20,8 +20,5 @@ export const KeyTypes = [
// For buttons that modify the broader keypad state (e.g., by changing
// the visible pane).
"KEYPAD_NAVIGATION",
- // For buttons that house multiple buttons and have no action
- // themselves.
- "MANY",
];
export type KeyType = (typeof KeyTypes)[number];
diff --git a/packages/math-input/src/types.ts b/packages/math-input/src/types.ts
index 505f640a4c..d5c3648fcb 100644
--- a/packages/math-input/src/types.ts
+++ b/packages/math-input/src/types.ts
@@ -9,20 +9,13 @@ export type IconConfig = {
data: string;
};
-export type NonManyKeyConfig = {
+export type KeyConfig = {
id: Key;
- type: Exclude;
+ type: KeyType;
icon: IconConfig;
ariaLabel: string;
};
-export type ManyKeyConfig = Omit & {
- type: Extract;
- childKeyIds: ReadonlyArray;
-};
-
-export type KeyConfig = NonManyKeyConfig | ManyKeyConfig;
-
export type KeypadConfiguration = {
keypadType: KeypadType;
extraKeys?: ReadonlyArray;
diff --git a/packages/perseus-editor/src/__stories__/flags-for-api-options.ts b/packages/perseus-editor/src/__stories__/flags-for-api-options.ts
index 7b454dd203..479768047a 100644
--- a/packages/perseus-editor/src/__stories__/flags-for-api-options.ts
+++ b/packages/perseus-editor/src/__stories__/flags-for-api-options.ts
@@ -22,6 +22,7 @@ export const flags = {
"start-coords-ui-phase-2": true,
"start-coords-ui-point": true,
"start-coords-ui-polygon": true,
+ "start-coords-ui-angle": true,
},
} satisfies APIOptions["flags"];
diff --git a/packages/perseus-editor/src/__stories__/interactive-graph-editor.stories.tsx b/packages/perseus-editor/src/__stories__/interactive-graph-editor.stories.tsx
index 02ce4e882d..f672376960 100644
--- a/packages/perseus-editor/src/__stories__/interactive-graph-editor.stories.tsx
+++ b/packages/perseus-editor/src/__stories__/interactive-graph-editor.stories.tsx
@@ -8,11 +8,12 @@ import * as React from "react";
import {EditorPage} from "..";
import {
+ angleWithStartingCoordsQuestion,
circleWithStartingCoordsQuestion,
linearSystemWithStartingCoordsQuestion,
linearWithStartingCoordsQuestion,
pointQuestionWithStartingCoords,
- polygonQuestion,
+ polygonWithStartingCoordsQuestion,
quadraticWithStartingCoordsQuestion,
rayWithStartingCoordsQuestion,
segmentWithLockedFigures,
@@ -111,7 +112,19 @@ export const InteractiveGraphPoint = (): React.ReactElement => (
);
export const InteractiveGraphPolygon = (): React.ReactElement => {
- return ;
+ return (
+
+ );
+};
+
+export const InteractiveGraphAngle = (): React.ReactElement => {
+ return (
+
+ );
};
export const MafsWithLockedFiguresCurrent = (): React.ReactElement => {
diff --git a/packages/perseus-editor/src/components/__tests__/util.test.ts b/packages/perseus-editor/src/components/__tests__/util.test.ts
index b27986297c..67dd1c28c7 100644
--- a/packages/perseus-editor/src/components/__tests__/util.test.ts
+++ b/packages/perseus-editor/src/components/__tests__/util.test.ts
@@ -365,6 +365,26 @@ describe("getDefaultGraphStartCoords", () => {
[-3, -3],
]);
});
+
+ test("should get default start coords for an angle graph", () => {
+ // Arrange
+ const graph: PerseusGraphType = {type: "angle"};
+ const range = [
+ [-10, 10],
+ [-10, 10],
+ ] satisfies [Range, Range];
+ const step = [1, 1] satisfies [number, number];
+
+ // Act
+ const defaultCoords = getDefaultGraphStartCoords(graph, range, step);
+
+ // Default correct answer is 20 degree angle at (0, 0)
+ expect(defaultCoords).toEqual([
+ [7, 0],
+ [0, 0],
+ [6.5778483455013586, 2.394141003279681],
+ ]);
+ });
});
describe("getSinusoidEquation", () => {
diff --git a/packages/perseus-editor/src/components/start-coords-angle.tsx b/packages/perseus-editor/src/components/start-coords-angle.tsx
new file mode 100644
index 0000000000..34f8f0f0f3
--- /dev/null
+++ b/packages/perseus-editor/src/components/start-coords-angle.tsx
@@ -0,0 +1,28 @@
+import {View} from "@khanacademy/wonder-blocks-core";
+import * as React from "react";
+
+import type {Coord, PerseusGraphType} from "@khanacademy/perseus";
+
+type Props = {
+ startCoords: [Coord, Coord, Coord];
+ onChange: (startCoords: PerseusGraphType["startCoords"]) => void;
+};
+
+const StartCoordsAngle = (props: Props) => {
+ const {startCoords} = props;
+ return (
+
+ WIP
+
Start coords:
+ {startCoords.map((coord, index) => {
+ return (
+
+ {`Point ${index + 1}: (${coord[0]}, ${coord[1]})`}
+
+ );
+ })}
+
+ );
+};
+
+export default StartCoordsAngle;
diff --git a/packages/perseus-editor/src/components/start-coords-settings.tsx b/packages/perseus-editor/src/components/start-coords-settings.tsx
index 4bf5bc2947..6018780a5f 100644
--- a/packages/perseus-editor/src/components/start-coords-settings.tsx
+++ b/packages/perseus-editor/src/components/start-coords-settings.tsx
@@ -1,5 +1,6 @@
import {vector as kvector} from "@khanacademy/kmath";
import {
+ getAngleCoords,
getCircleCoords,
getLineCoords,
getLinearSystemCoords,
@@ -17,6 +18,7 @@ import arrowCounterClockwise from "@phosphor-icons/core/bold/arrow-counter-clock
import * as React from "react";
import Heading from "./heading";
+import StartCoordsAngle from "./start-coords-angle";
import StartCoordsCircle from "./start-coords-circle";
import StartCoordsLine from "./start-coords-line";
import StartCoordsMultiline from "./start-coords-multiline";
@@ -105,6 +107,14 @@ const StartCoordsSettingsInner = (props: Props) => {
onChange={onChange}
/>
);
+ case "angle":
+ const angleCoords = getAngleCoords({graph: props, range, step});
+ return (
+
+ );
default:
return null;
}
diff --git a/packages/perseus-editor/src/components/util.ts b/packages/perseus-editor/src/components/util.ts
index e0d61de1a0..3b15594fd7 100644
--- a/packages/perseus-editor/src/components/util.ts
+++ b/packages/perseus-editor/src/components/util.ts
@@ -1,5 +1,6 @@
import {vector as kvector} from "@khanacademy/kmath";
import {
+ getAngleCoords,
getCircleCoords,
getLineCoords,
getLinearSystemCoords,
@@ -208,6 +209,12 @@ export function getDefaultGraphStartCoords(
range,
step,
);
+ case "angle":
+ return getAngleCoords({
+ graph: {...graph, startCoords: undefined},
+ range,
+ step,
+ });
default:
return undefined;
}
@@ -283,6 +290,7 @@ export const shouldShowStartCoordsUI = (flags, graph) => {
const startCoordsPhase2 = flags?.mafs?.["start-coords-ui-phase-2"];
const startCoordsPoint = flags?.mafs?.["start-coords-ui-point"];
const startCoordsPolygon = flags?.mafs?.["start-coords-ui-polygon"];
+ const startCoordsAngle = flags?.mafs?.["start-coords-ui-angle"];
if (startCoordsPhase1 && startCoordsUiPhase1Types.includes(graph.type)) {
return true;
@@ -292,6 +300,10 @@ export const shouldShowStartCoordsUI = (flags, graph) => {
return true;
}
+ if (startCoordsAngle && graph.type === "angle") {
+ return true;
+ }
+
if (
startCoordsPoint &&
graph.type === "point" &&
diff --git a/packages/perseus-editor/src/widgets/__tests__/interactive-graph-editor.test.tsx b/packages/perseus-editor/src/widgets/__tests__/interactive-graph-editor.test.tsx
index 0309c5b28f..4b10a9940f 100644
--- a/packages/perseus-editor/src/widgets/__tests__/interactive-graph-editor.test.tsx
+++ b/packages/perseus-editor/src/widgets/__tests__/interactive-graph-editor.test.tsx
@@ -706,6 +706,7 @@ describe("InteractiveGraphEditor", () => {
"start-coords-ui-phase-2": false,
"start-coords-ui-point": false,
"start-coords-ui-polygon": false,
+ "start-coords-ui-angle": false,
},
},
}}
@@ -765,6 +766,7 @@ describe("InteractiveGraphEditor", () => {
"start-coords-ui-phase-2": true,
"start-coords-ui-point": false,
"start-coords-ui-polygon": false,
+ "start-coords-ui-angle": false,
},
},
}}
@@ -824,6 +826,7 @@ describe("InteractiveGraphEditor", () => {
"start-coords-ui-phase-2": false,
"start-coords-ui-point": true,
"start-coords-ui-polygon": false,
+ "start-coords-ui-angle": false,
},
},
}}
@@ -883,6 +886,67 @@ describe("InteractiveGraphEditor", () => {
"start-coords-ui-phase-2": false,
"start-coords-ui-point": false,
"start-coords-ui-polygon": true,
+ "start-coords-ui-angle": false,
+ },
+ },
+ }}
+ graph={{type}}
+ correct={{type}}
+ />,
+ {
+ wrapper: RenderStateRoot,
+ },
+ );
+
+ // Assert
+ if (shouldRender) {
+ expect(
+ await screen.findByRole("button", {
+ name: "Use default start coordinates",
+ }),
+ ).toBeInTheDocument();
+ } else {
+ expect(
+ screen.queryByRole("button", {
+ name: "Use default start coordinates",
+ }),
+ ).toBeNull();
+ }
+ },
+ );
+
+ test.each`
+ type | shouldRender
+ ${"linear"} | ${false}
+ ${"ray"} | ${false}
+ ${"linear-system"} | ${false}
+ ${"segment"} | ${false}
+ ${"circle"} | ${false}
+ ${"quadratic"} | ${false}
+ ${"sinusoid"} | ${false}
+ ${"polygon"} | ${false}
+ ${"angle"} | ${true}
+ ${"point"} | ${false}
+ `(
+ "should render for $type graphs if angle flag is on: $shouldRender",
+ async ({type, shouldRender}) => {
+ // Arrange
+
+ // Act
+ render(
+