Skip to content

Commit

Permalink
feat: Allow pass-through script props in ScrollRestoration (#2879)
Browse files Browse the repository at this point in the history
  • Loading branch information
chaance committed Dec 1, 2022
1 parent da0c278 commit 200eea9
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-files-trade.md
@@ -0,0 +1,5 @@
---
"@remix-run/react": patch
---

Allow pass-through props to be passed to the script rendered by `ScrollRestoration`
104 changes: 104 additions & 0 deletions packages/remix-react/__tests__/scroll-restoration-test.tsx
@@ -0,0 +1,104 @@
import * as React from "react";
import { MemoryRouter, Outlet } from "react-router-dom";
import { render, screen } from "@testing-library/react";

import { LiveReload, RemixEntryContext, Scripts } from "../components";
import type { RemixEntryContextType } from "../components";
import { ScrollRestoration } from "../scroll-restoration";

import "@testing-library/jest-dom/extend-expect";

function AppShell({ children }: { children: React.ReactNode }) {
return (
<React.Fragment>
<Outlet />
{children}
<Scripts />
<LiveReload />
</React.Fragment>
);
}

describe("<ScrollRestoration />", () => {
function withContext(stuff: JSX.Element) {
let context: RemixEntryContextType = {
routeModules: { idk: { default: () => null } },
manifest: {
routes: {
idk: {
hasLoader: true,
hasAction: false,
hasCatchBoundary: false,
hasErrorBoundary: false,
id: "idk",
module: "idk",
},
},
entry: { imports: [], module: "" },
url: "",
version: "",
},
matches: [],
clientRoutes: [
{
id: "idk",
path: "idk",
hasLoader: true,
element: "",
module: "",
async action() {
return {};
},
async loader() {
return {};
},
},
],
routeData: {},
appState: {} as any,
transitionManager: {
getState() {
return {
transition: {},
};
},
} as any,
};
return (
<RemixEntryContext.Provider value={context}>
<MemoryRouter>{stuff}</MemoryRouter>
</RemixEntryContext.Provider>
);
}

it("should render a <script> tag", () => {
render(
withContext(
<AppShell>
<ScrollRestoration data-testid="scroll-script" />
</AppShell>
)
);
let script = screen.getByTestId("scroll-script");
expect(script instanceof HTMLScriptElement).toBe(true);
});

it("should pass props to <script>", () => {
render(
withContext(
<AppShell>
<ScrollRestoration
data-testid="scroll-script"
nonce="hello"
crossOrigin="anonymous"
/>
</AppShell>
)
);
let script = screen.getByTestId("scroll-script");
expect(script).toHaveAttribute("nonce", "hello");
expect(script).toHaveAttribute("crossorigin", "anonymous");
});

it.todo("should restore scroll position");
});
4 changes: 2 additions & 2 deletions packages/remix-react/components.tsx
Expand Up @@ -65,7 +65,7 @@ import type {
////////////////////////////////////////////////////////////////////////////////
// RemixEntry

interface RemixEntryContextType {
export interface RemixEntryContextType {
manifest: AssetsManifest;
matches: BaseRouteMatch<ClientRoute>[];
routeData: RouteData;
Expand Down Expand Up @@ -890,7 +890,7 @@ export function Meta() {
*/
let isHydrated = false;

type ScriptProps = Omit<
export type ScriptProps = Omit<
React.HTMLProps<HTMLScriptElement>,
| "children"
| "async"
Expand Down
5 changes: 3 additions & 2 deletions packages/remix-react/scroll-restoration.tsx
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import { useLocation } from "react-router-dom";

import { useBeforeUnload, useTransition } from "./components";
import type { ScriptProps } from "./components";

let STORAGE_KEY = "positions";

Expand All @@ -20,7 +21,7 @@ if (typeof document !== "undefined") {
*
* @see https://remix.run/api/remix#scrollrestoration
*/
export function ScrollRestoration({ nonce = undefined }: { nonce?: string }) {
export function ScrollRestoration(props: ScriptProps) {
useScrollRestoration();

// wait for the browser to restore it on its own
Expand Down Expand Up @@ -54,7 +55,7 @@ export function ScrollRestoration({ nonce = undefined }: { nonce?: string }) {

return (
<script
nonce={nonce}
{...props}
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: `(${restoreScroll})(${JSON.stringify(STORAGE_KEY)})`,
Expand Down

0 comments on commit 200eea9

Please sign in to comment.