Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(example): add an example of using emotion css prop #1607

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
- GregBrimble
- hardingmatt
- HenryVogt
- himorishige
- hkan
- Holben888
- hollandThomas
Expand Down
5 changes: 5 additions & 0 deletions examples/emotion-css-prop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules

/.cache
/build
/public/build
26 changes: 26 additions & 0 deletions examples/emotion-css-prop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Example app with [Emotion](https://emotion.sh/docs/introduction) - css Prop

This example features how to use [Emotion](https://emotion.sh/docs/introduction) - css Prop with Remix.

## Preview

Open this example on [CodeSandbox](https://codesandbox.com):

[![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/remix-run/remix/tree/main/examples/emotion-css-prop)

## Example

This example shows how to use Emotion - css Prop with Remix.

Relevant files:

- [app/root.tsx](./app/root.tsx) - This is where we render the app and if we're rendering on the server we have placeholder text of __STYLES__.
- [app/entry.server.tsx](./app/entry.server.tsx) - This is where we render the app on the server and replace __STYLES__ with the styles that emotion collect.
- [app/routes/index.tsx](./app/routes/index.tsx) - Here's where we use the css Prop to styling component.
- [tsconfig.json](./tsconfig.json) - Add `jsxImportSource` to use the css Prop in tsx file.

## Related Links

- [Emotion](https://emotion.sh/docs/introduction)
- [The css Prop](https://emotion.sh/docs/css-prop)
- [emotion-reset](https://github.com/sayegh7/emotion-reset)
4 changes: 4 additions & 0 deletions examples/emotion-css-prop/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { hydrate } from "react-dom";
import { RemixBrowser } from "remix";

hydrate(<RemixBrowser />, document);
56 changes: 56 additions & 0 deletions examples/emotion-css-prop/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import createCache from "@emotion/cache";
import { CacheProvider, css, Global } from "@emotion/react";
import createEmotionServer from "@emotion/server/create-instance";
import emotionReset from "emotion-reset";
import { renderToString } from "react-dom/server";
import type { EntryContext } from "remix";
import { RemixServer } from "remix";
import { StylesProvider } from "./styles-context";

const key = "emotion";
const cache = createCache({ key });
const { extractCriticalToChunks, constructStyleTagsFromChunks } =
createEmotionServer(cache);

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const html = renderToString(
<CacheProvider value={cache}>
<StylesProvider value={null}>
<RemixServer context={remixContext} url={request.url} />
</StylesProvider>
</CacheProvider>
);

const chunks = extractCriticalToChunks(html);
const styles = constructStyleTagsFromChunks(chunks);

const markup = renderToString(
<StylesProvider value={styles}>
{/* Set the global style. */}
<Global
styles={css`
${emotionReset}
*, *::after, *::before {
box-sizing: border-box;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}
`}
/>
<RemixServer context={remixContext} url={request.url} />
</StylesProvider>
);

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

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders
});
}
51 changes: 51 additions & 0 deletions examples/emotion-css-prop/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useCatch
} from "remix";
import { useStyles } from "./styles-context";

export default function App() {
const styles = useStyles();
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
{typeof document === "undefined" ? null : styles}
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

export function CatchBoundary() {
const caught = useCatch();
if (caught.status === 404) {
return (
<div>
<h1>{caught.statusText}</h1>
</div>
);
}
throw new Error(`Unhandled error: ${caught.status}`);
}

export function ErrorBoundary({ error }: { error: Error }) {
return (
<div>
<h1>{error.message}</h1>
</div>
);
}
46 changes: 46 additions & 0 deletions examples/emotion-css-prop/app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/** @jsx jsx */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does esbuild respect this pragma?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esbuild supports jsx annotations.
However, it seems that jsxImportSource support is not yet implemented without babel support.

ref:
Support JSX annotation
evanw/esbuild#138

Support /** @jsx pragma
evanw/esbuild#389

Add support for jsxImportSource
evanw/esbuild#1172

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is limited, it seems to be possible to remove the pragma by adopting the patch in this issue.

import { css, jsx } from "@emotion/react";
import { useEffect, useState } from "react";
import { Link, useCatch } from "remix";

// Object Styles
const wrapperStyle = {
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
};

// String Styles
const headingStyle = css`
font-size: 2rem;
color: hotpink;
transition: color 0.5s 0s ease;
`;

const headingDefaultStyle = css`
font-size: 2rem;
`;

export default function Index() {
const [state, setState] = useState(false);

useEffect(() => {
new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
setState(true);
});
}, []);

return (
<div>
<header>
<Link to="/">Top Page</Link> | <Link to="/sub">Sub Page</Link>
</header>
<div css={wrapperStyle}>
<h1 css={state ? headingStyle : headingDefaultStyle}>
Welcome to Remix (With Emotion css Prop)
</h1>
</div>
</div>
);
}
46 changes: 46 additions & 0 deletions examples/emotion-css-prop/app/routes/sub.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/** @jsx jsx */
import { css, jsx } from "@emotion/react";
import { useEffect, useState } from "react";
import { Link } from "remix";

// Object Styles
const wrapperStyle = {
height: "100vh",
display: "flex",
alignItems: "center",
justifyContent: "center"
};

// String Styles
const headingStyle = css`
font-size: 2rem;
color: blue;
transition: color 0.5s 0s ease;
`;

const headingDefaultStyle = css`
font-size: 2rem;
`;

export default function Index() {
const [state, setState] = useState(false);

useEffect(() => {
new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
setState(true);
});
}, []);

return (
<div>
<header>
<Link to="/">Top Page</Link> | <Link to="/sub">Sub Page</Link>
</header>
<div css={wrapperStyle}>
<h1 css={state ? headingStyle : headingDefaultStyle}>
Welcome to SubPage (With Emotion css Prop)
</h1>
</div>
</div>
);
}
4 changes: 4 additions & 0 deletions examples/emotion-css-prop/app/styles-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import * as React from "react";
const StylesContext = React.createContext<null | React.ReactNode>(null);
export const StylesProvider = StylesContext.Provider;
export const useStyles = () => React.useContext(StylesContext);
Loading