diff --git a/apps/web/src/components/specification/SpecificationFormView.tsx b/apps/web/src/components/specification/SpecificationFormView.tsx index 05df9f6d1..6c4e4b0e0 100644 --- a/apps/web/src/components/specification/SpecificationFormView.tsx +++ b/apps/web/src/components/specification/SpecificationFormView.tsx @@ -6,11 +6,12 @@ import { GridCol, SegmentedControl, Stack, + useMantineTheme, } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { propOr } from "ramda"; import { isFunction, isNilOrEmpty, isNotNilOrEmpty } from "ramda-adjunct"; -import { FC, useCallback, useState } from "react"; +import { FC, useCallback, useEffect, useRef, useState } from "react"; import { TbLayoutColumns, TbLayoutList } from "react-icons/tb"; import { DecodingPreview } from "./components/DecodingPreview"; import { SpecificationForm } from "./form/SpecificationForm"; @@ -21,8 +22,8 @@ import { useSpecForm, } from "./form/context"; import { - specABIValidation, specAbiParamValidation, + specABIValidation, specConditionalsValidation, specEncodedDataValidation, specModeValidation, @@ -30,6 +31,7 @@ import { specSliceInstructionsValidation, } from "./form/validations"; import { JSON_ABI, Specification } from "./types"; +import { useMediaQuery } from "@mantine/hooks"; type Layout = "split_screen" | "stack_screen"; const getInitialValues = (spec?: Specification): SpecFormValues => { @@ -65,6 +67,7 @@ export const SpecificationFormView: FC = ({ onSuccess, }) => { const [layout, setLayout] = useState("split_screen"); + const lastSelectedLayout = useRef(layout); const colSpan = layout === "split_screen" ? 6 : 12; const form = useSpecForm({ initialValues: getInitialValues(specification), @@ -79,6 +82,8 @@ export const SpecificationFormView: FC = ({ }, }); const { formMode } = form.getTransformedValues(); + const theme = useMantineTheme(); + const isSmallDevice = useMediaQuery(`(max-width:${theme.breakpoints.sm})`); const onFinished = useCallback( (spec: Specification) => { @@ -108,37 +113,46 @@ export const SpecificationFormView: FC = ({ }); }, []); + useEffect(() => { + setLayout(isSmallDevice ? "stack_screen" : lastSelectedLayout.current); + }, [isSmallDevice]); + return ( - - { - setLayout(value as Layout); - }} - data={[ - { - value: "split_screen", - label: ( -
- - Split View -
- ), - }, - { - value: "stack_screen", - label: ( -
- - List View -
- ), - }, - ]} - /> -
+ {!isSmallDevice && ( + + { + const nextValue = value as Layout; + setLayout(nextValue); + lastSelectedLayout.current = nextValue; + }} + data={[ + { + value: "split_screen", + label: ( +
+ + Split View +
+ ), + }, + { + value: "stack_screen", + label: ( +
+ + List View +
+ ), + }, + ]} + /> +
+ )} + diff --git a/apps/web/src/components/specification/form/fields/ByteSlices.tsx b/apps/web/src/components/specification/form/fields/ByteSlices.tsx index 1347f67cb..29d798569 100644 --- a/apps/web/src/components/specification/form/fields/ByteSlices.tsx +++ b/apps/web/src/components/specification/form/fields/ByteSlices.tsx @@ -78,11 +78,12 @@ const InstructionsReview: FC = ({ slices, onSliceChange }) => { Review your definition - + diff --git a/apps/web/test/components/specification/SpecificationFormView.test.tsx b/apps/web/test/components/specification/SpecificationFormView.test.tsx index 0b3bd3c0a..c752381bd 100644 --- a/apps/web/test/components/specification/SpecificationFormView.test.tsx +++ b/apps/web/test/components/specification/SpecificationFormView.test.tsx @@ -19,6 +19,20 @@ import withMantineTheme from "../../utils/WithMantineTheme"; import { encodedDataSamples } from "./encodedData.stubs"; import { JotaiTestProvider } from "./jotaiHelpers"; import { erc1155JSONABISpecStub } from "./specification.stubs"; +import * as mantineHooks from "@mantine/hooks"; + +vi.mock("@mantine/hooks", async () => { + const actual = await vi.importActual("@mantine/hooks"); + + return { + ...actual, + useMediaQuery: vi.fn(), + }; +}); + +const useMediaQueryMock = vi.mocked(mantineHooks.useMediaQuery, { + partial: true, +}); const View = withMantineTheme(SpecificationFormView); type Props = Parameters[0]; @@ -831,4 +845,24 @@ describe("Specification Form View", () => { }); }); }); + + describe("Layout", () => { + it("should hide view switch on small devices", async () => { + useMediaQueryMock.mockReturnValue(true); + await act(async () => render()); + + expect(() => + screen.getByTestId("specification-creation-view-switch"), + ).toThrow("Unable to find an element"); + }); + + it("should show view switch on large devices", async () => { + useMediaQueryMock.mockReturnValue(false); + await act(async () => render()); + + expect( + screen.getByTestId("specification-creation-view-switch"), + ).toBeInTheDocument(); + }); + }); });