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 ( - - - {id} - - - placeholder - - - ); 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( +