diff --git a/.changeset/shaggy-moles-promise.md b/.changeset/shaggy-moles-promise.md new file mode 100644 index 0000000000..91035224e1 --- /dev/null +++ b/.changeset/shaggy-moles-promise.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": patch +--- + +Internal: wrap the Mafs `useMovable` hook, creating a seam where we can add new functionality. diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/circle.tsx b/packages/perseus/src/widgets/interactive-graphs/graphs/circle.tsx index 4d49482b5a..ab49ae0bac 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graphs/circle.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/circle.tsx @@ -1,4 +1,4 @@ -import {useMovable, vec} from "mafs"; +import {vec} from "mafs"; import * as React from "react"; import {useRef} from "react"; @@ -8,6 +8,7 @@ import useGraphConfig from "../reducer/use-graph-config"; import {snap} from "../utils"; import {StyledMovablePoint} from "./components/movable-point"; +import {useDraggable} from "./use-draggable"; import { useTransformDimensionsToPixels, useTransformVectorsToPixels, @@ -49,7 +50,7 @@ function MovableCircle(props: { const draggableRef = useRef(null); - const {dragging} = useMovable({ + const {dragging} = useDraggable({ gestureTarget: draggableRef, point: center, onMove, diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-line.test.tsx b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-line.test.tsx index f2ca5aa4d4..661d326e38 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-line.test.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-line.test.tsx @@ -1,20 +1,13 @@ import {render} from "@testing-library/react"; -import * as MafsLibrary from "mafs"; +import {Mafs} from "mafs"; import React from "react"; +import * as UseDraggableModule from "../use-draggable"; + import {MovableLine, trimRange} from "./movable-line"; import type {Interval, vec} from "mafs"; -jest.mock("mafs", () => { - const originalModule = jest.requireActual("mafs"); - return { - __esModule: true, - ...originalModule, - useMovable: jest.fn(), - }; -}); - describe("trimRange", () => { it("does not trim smaller than [[0, 0], [0, 0]]", () => { const graphDimensionsInPixels: vec.Vector2 = [1, 1]; @@ -78,12 +71,11 @@ describe("trimRange", () => { }); describe("Rendering", () => { - let useMovableMock: jest.SpyInstance; - const Mafs = MafsLibrary.Mafs; + let useDraggable: jest.SpyInstance; beforeEach(() => { - useMovableMock = jest - .spyOn(MafsLibrary, "useMovable") + useDraggable = jest + .spyOn(UseDraggableModule, "useDraggable") .mockReturnValue({dragging: false}); }); @@ -159,7 +151,7 @@ describe("Rendering", () => { expect(line?.classList).not.toContain("movable-dragging"); // Verify dragging state - useMovableMock.mockReturnValue({dragging: true}); + useDraggable.mockReturnValue({dragging: true}); container = render( (null); - useMovable({ + useDraggable({ gestureTarget: keyboardHandleRef, point, onMove: onMovePoint, @@ -87,7 +88,7 @@ function useControlPoint( }); const visiblePointRef = useRef(null); - const {dragging} = useMovable({ + const {dragging} = useDraggable({ gestureTarget: visiblePointRef, point, onMove: onMovePoint, @@ -156,7 +157,7 @@ const Line = (props: LineProps) => { } const line = useRef(null); - const {dragging} = useMovable({ + const {dragging} = useDraggable({ gestureTarget: line, point: start, onMove: (newPoint) => { diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.test.tsx b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.test.tsx index 34e5b0249e..5b8416a5f2 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.test.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.test.tsx @@ -1,21 +1,13 @@ import Tooltip from "@khanacademy/wonder-blocks-tooltip"; import {render} from "@testing-library/react"; -import * as MafsLibrary from "mafs"; +import {Mafs} from "mafs"; import React from "react"; import * as ReducerGraphConfig from "../../reducer/use-graph-config"; +import * as UseDraggableModule from "../use-draggable"; import {StyledMovablePoint} from "./movable-point"; -jest.mock("mafs", () => { - const originalModule = jest.requireActual("mafs"); - return { - __esModule: true, - ...originalModule, - useMovable: jest.fn(), - }; -}); - jest.mock("@khanacademy/wonder-blocks-tooltip", () => { const originalModule = jest.requireActual( "@khanacademy/wonder-blocks-tooltip", @@ -33,8 +25,7 @@ const TooltipMock = ({children}) => { describe("StyledMovablePoint", () => { let useGraphConfigMock: jest.SpyInstance; - let useMovableMock: jest.SpyInstance; - const Mafs = MafsLibrary.Mafs; + let useDraggableMock: jest.SpyInstance; const baseGraphConfigContext = { snapStep: 1, range: [ @@ -47,8 +38,8 @@ describe("StyledMovablePoint", () => { beforeEach(() => { useGraphConfigMock = jest.spyOn(ReducerGraphConfig, "default"); - useMovableMock = jest - .spyOn(MafsLibrary, "useMovable") + useDraggableMock = jest + .spyOn(UseDraggableModule, "useDraggable") .mockReturnValue({dragging: false}); }); @@ -142,7 +133,7 @@ describe("StyledMovablePoint", () => { describe("Hairlines", () => { it("Shows hairlines when dragging and 'markings' are NOT set to 'none'", () => { useGraphConfigMock.mockReturnValue(baseGraphConfigContext); - useMovableMock.mockReturnValue({dragging: true}); + useDraggableMock.mockReturnValue({dragging: true}); const {container} = render( {}} />, @@ -174,7 +165,7 @@ describe("StyledMovablePoint", () => { const graphStateContext = {...baseGraphConfigContext}; graphStateContext.markings = "none"; useGraphConfigMock.mockReturnValue(graphStateContext); - useMovableMock.mockReturnValue({dragging: true}); + useDraggableMock.mockReturnValue({dragging: true}); const {container} = render( {}} />, diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.tsx b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.tsx index c286400172..9eb90d278f 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/components/movable-point.tsx @@ -1,10 +1,10 @@ import {color as WBColor} from "@khanacademy/wonder-blocks-tokens"; -import {useMovable} from "mafs"; import * as React from "react"; import {useRef} from "react"; import useGraphConfig from "../../reducer/use-graph-config"; import {snap} from "../../utils"; +import {useDraggable} from "../use-draggable"; import {MovablePointView} from "./movable-point-view"; @@ -24,7 +24,7 @@ export const StyledMovablePoint = (props: Props) => { const elementRef = useRef(null); const {point, onMove, cursor, color = WBColor.blue, snapTo} = props; const snapToValue = snapTo ?? "grid"; - const {dragging} = useMovable({ + const {dragging} = useDraggable({ gestureTarget: elementRef, point, onMove, diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/polygon.tsx b/packages/perseus/src/widgets/interactive-graphs/graphs/polygon.tsx index eda894e536..849664ea3c 100644 --- a/packages/perseus/src/widgets/interactive-graphs/graphs/polygon.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/polygon.tsx @@ -1,4 +1,4 @@ -import {Polygon, useMovable, vec} from "mafs"; +import {Polygon, vec} from "mafs"; import * as React from "react"; import {moveAll, movePoint} from "../reducer/interactive-graph-action"; @@ -7,6 +7,7 @@ import {TARGET_SIZE, snap} from "../utils"; import {Angle} from "./components/angle"; import {StyledMovablePoint} from "./components/movable-point"; import {TextLabel} from "./components/text-label"; +import {useDraggable} from "./use-draggable"; import {getLines} from "./utils"; import type {MafsGraphProps, PolygonGraphState} from "../types"; @@ -28,7 +29,7 @@ export const PolygonGraph = (props: Props) => { const ref = React.useRef(null); const dragReferencePoint = points[0]; const snapToValue = snapTo ?? "grid"; - const {dragging} = useMovable({ + const {dragging} = useDraggable({ gestureTarget: ref, point: dragReferencePoint, onMove: (newPoint) => { diff --git a/packages/perseus/src/widgets/interactive-graphs/graphs/use-draggable.ts b/packages/perseus/src/widgets/interactive-graphs/graphs/use-draggable.ts new file mode 100644 index 0000000000..e466fa1c7b --- /dev/null +++ b/packages/perseus/src/widgets/interactive-graphs/graphs/use-draggable.ts @@ -0,0 +1,19 @@ +import {useMovable} from "mafs"; + +import type {vec} from "mafs"; +import type {RefObject} from "react"; + +type Params = { + gestureTarget: RefObject; + onMove: (point: vec.Vector2) => unknown; + point: vec.Vector2; + constrain: (point: vec.Vector2) => vec.Vector2; +}; + +type DragState = { + dragging: boolean; +}; + +export function useDraggable(params: Params): DragState { + return useMovable(params); +}