Skip to content

Commit

Permalink
[pigment-css][example] Add example project with Remix (#41700)
Browse files Browse the repository at this point in the history
  • Loading branch information
brijeshb42 authored Apr 1, 2024
1 parent fbf6875 commit b338f3f
Show file tree
Hide file tree
Showing 13 changed files with 544 additions and 0 deletions.
8 changes: 8 additions & 0 deletions examples/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ module.exports = {
// create-vite generates .jsx
'react/jsx-filename-extension': 'off',
},
overrides: [
{
files: ['pigment-css-remix-ts/**/*.*'],
rules: {
'react/react-in-jsx-scope': 'off',
},
},
],
};
5 changes: 5 additions & 0 deletions examples/pigment-css-remix-ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules

/.cache
/build
.env
3 changes: 3 additions & 0 deletions examples/pigment-css-remix-ts/.stackblitzrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"startCommand": "npm run dev"
}
34 changes: 34 additions & 0 deletions examples/pigment-css-remix-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Pigment CSS - Remix with TypeScript example project

## How to use

Download the example [or clone the repo](https://github.com/mui/material-ui):

<!-- #default-branch-switch -->

```bash
curl https://codeload.github.com/mui/material-ui/tar.gz/next | tar -xz --strip=2 material-ui-next/examples/pigment-css-remix-ts
cd pigment-css-remix-ts
```

Install it and run:

```bash
npm install
npm run dev
```

or:

<!-- #default-branch-switch -->

[![Edit on StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mui/material-ui/tree/next/examples/pigment-css-remix-ts)

[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/github/mui/material-ui/tree/next/examples/pigment-css-remix-ts)

## Learn more

To learn more about this example:

- [Pigment CSS documentation](https://github.com/mui/material-ui/blob/next/packages/pigment-css-react/README.md) - learn more about Pigment CSS features and APIs.
- [Remix documentation](https://remix.run/docs) - learn about Remix features and APIs.
18 changes: 18 additions & 0 deletions examples/pigment-css-remix-ts/app/augment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { ExtendTheme } from '@pigment-css/react/theme';

declare module '@pigment-css/react/theme' {
export interface ThemeArgs {
theme: ExtendTheme<{
colorScheme: 'light' | 'dark';
tokens: {
palette: {
background: string;
foreground: string;
primary: string;
primaryForeground: string;
border: string;
};
};
}>;
}
}
18 changes: 18 additions & 0 deletions examples/pigment-css-remix-ts/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from '@remix-run/react';
import * as React from 'react';
import * as ReactDOMClient from 'react-dom/client';

React.startTransition(() => {
ReactDOMClient.hydrateRoot(
document,
<React.StrictMode>
<RemixBrowser />
</React.StrictMode>,
);
});
122 changes: 122 additions & 0 deletions examples/pigment-css-remix-ts/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import { PassThrough } from 'node:stream';

import type { AppLoadContext, EntryContext } from '@remix-run/node';
import { createReadableStreamFromReadable } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import { isbot } from 'isbot';
import * as ReactDOMServer from 'react-dom/server';

const ABORT_DELAY = 5_000;

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext,
) {
return isbot(request.headers.get('user-agent') || '')
? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
: handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onAllReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set('Content-Type', 'text/html');

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
}),
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
},
);

setTimeout(abort, ABORT_DELAY);
});
}

function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = ReactDOMServer.renderToPipeableStream(
<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
{
onShellReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set('Content-Type', 'text/html');

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
}),
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
},
);

setTimeout(abort, ABORT_DELAY);
});
}
31 changes: 31 additions & 0 deletions examples/pigment-css-remix-ts/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react';
import { css } from '@pigment-css/react';
import '@pigment-css/react/styles.css';

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<Meta />
<Links />
</head>
<body
className={css`
padding: 0;
margin: 0;
`}
>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}

export default function App() {
return <Outlet />;
}
Loading

0 comments on commit b338f3f

Please sign in to comment.